2013-02-13 87 views
2

我正在维护一个字典,用于跟踪对象之间的相似性。
例如,这本词典可以是这样的:字典中的复合键

similarities = { 
p1: {p2: v12, p3:v13, p4:v14}, 
p2: {p1: v21, p3:v23, p4:v24}, 
p3: {p1: v31, p2:v32, p4:v34}, 
p4: {p1: v41, p2:v42, p4:v43} 
} 

注意,该相似性度量是对称的。因此,similarities[p1][p2]similarities[p2][p1]相同,即v12 == v21

有时候,我需要从similarities[p1]消除p2;在这样做的时候,我需要从similarities的所有内部字典中删除p1p2
这是单调而低效的。

因此,而不是保持对称字典的,有保持字典,复合键,这样我可以查找similarities[p1,p2]的方法吗?

自从(p1, p2) != (p2, p1)以来,我无法真正使用tuple,我无法事先知道如何排序元组。

一个frozenset是我能想到的唯一的其他容器,但不会削减它,因为有可能仍处于similarities其他键的是包含p1p2作为一个组成部分。那么我可以用什么容器来解决这个问题?

技术信息:

  • 蟒蛇2.7
  • 总是会有在这个 “复合键”

谢谢

+2

'frozenset'似乎将解决您的问题,我 - 任何理由认为,有可能是更好的东西? – mgilson 2013-02-13 01:51:16

+0

你可以使用'similarities [p1,p2]'这样的语法吗? – Blender 2013-02-13 01:52:10

+0

@Blender:不,这是非法的语法,至多可以翻译成一个元组 – inspectorG4dget 2013-02-13 01:52:41

回答

1

我想用frozenset是唯一合乎逻辑的解决方案。你可以找到匹配只使用一个理解有交集测试值的一个键:

def remove_ab(ab, similarities): 
    return {k:v for k, v in similarities.items() if not ab & k} 

similarities = {frozenset({1, 2}): "v12", 
       frozenset({1, 3}): "v13", 
       frozenset({2, 3}): "v23", 
       frozenset({3, 4}): "v34"} 

similarities = remove_ab(frozenset({1, 2}), similarities 
print(similarities) # output is {frozenset({3, 4}): 'v34'} 
2

我可能只用一个确切2元假设对象是可散列的,则为frozenset

或者,如果他们对这些问题的任何明确定义和一致的顺序,你可以让他们在排序元组表示顺序。你可以写一个dict子类来为你透明地做到这一点,如果你想。

或者,你可以做这样的事情:

class SymmetricDict(dict): 
    def __getitem__(self, key): 
     if key in self: 
      return dict.__getitem__(self, key) 
     a, b = key 
     return dict.__getitem__(self, (b, a)) 

,类似的还有__setitem__

+0

我想你可能需要'dict .__ getitem __(self,key)'而不是'self [key]'来避免无限循环 – mgilson 2013-02-13 01:56:51

+0

@mgilson当然,我的意思是写这个,然后我的手指只是输入了错误的东西。 :)修正。 – Dougal 2013-02-13 01:57:30

+0

要“超级”或不要超级......这就是问题...... ;-)。 (就我个人而言,我倾向于不使用'超级') – mgilson 2013-02-13 01:59:11

0

如果P_对象是支持排序的类型,你可以在罗总使用两个元素的元组 - >喜订单?

+0

但是这并不能解决删除所有具有该'p_object'作为复合组成部分的键的问题 – inspectorG4dget 2013-02-13 01:56:34