2010-12-06 345 views
3

我在python中創建了一個算法,用於爲值對創建度量,其中m(v1, v2) == m(v2, v1)(即它是對稱的)。我的想法是編寫一本字典詞典,其中這些值以有效的內存方式存儲,以便可以按任意順序輕鬆檢索這些值。我喜歡繼承東西,理想情況下,我喜歡寫一個symmetric_dict,其中s_d[v1][v2]總是等於s_d[v2][v1],可能是通過根據某種排序關係檢查哪個v更大,然後切換它們以便更小的元素首先總是提到一個。即當撥打s_d[5][2] = 4時,字典的字典會將它們翻轉,使得它們實際上被存儲爲s_d[2][5] = 4,並且對於數據的檢索是相同的。 我對於更好的數據結構也非常開放,但我更喜歡一個帶有「is-a」關係的實現,它只是使用字典並預處理一些函數參數。對稱字典其中d [a] [b] == d [b] [a]

回答

2

這是一個看起來很有前途的略有不同的方法。儘管SymDict類不是dict子類,但其大部分行爲類似於一個,並且只涉及單個私有字典。我認爲一個有趣的功能是它保留了您似乎想要的自然[][]查找語法。

class SymDict(object): 
    def __init__(self, *args, **kwrds): 
     self._mapping = _SubSymDict(*args, **kwrds) 
    def __getitem__(self, key1): 
     self._mapping.set_key1(key1) 
     return self._mapping 
    def __setitem__(self, key1, value): 
     raise NotImplementedError 
    def __str__(self): 
     return '_mapping: ' + self._mapping.__str__() 
    def __getattr__(self, name): 
     return getattr(self._mapping, name) 

class _SubSymDict(dict): 
    def __init__(self, *args, **kwrds): 
     dict.__init__(self, *args, **kwrds) 
    def set_key1(self, key1): 
     self.key1 = key1 
    def __getitem__(self, key2): 
     return dict.__getitem__(self, frozenset((self.key1, key2))) 
    def __setitem__(self, key2, value): 
     dict.__setitem__(self, frozenset((self.key1, key2)), value) 

symdict = SymDict() 
symdict[2][4] = 24 
symdict[4][2] = 42 

print 'symdict[2][4]:', symdict[2][4] 
# symdict[2][4]: 42 
print 'symdict[4][2]:', symdict[4][2] 
# symdict[4][2]: 42 
print 'symdict:', symdict 
# symdict: _mapping: {frozenset([2, 4]): 42} 

print symdict.keys() 
# [frozenset([2, 4])] 
3

如圖所示,使用嵌套索引來做它將會非常困難。相反,最好使用元組作爲關鍵字。這樣可以對元組進行排序,並且可以訪問封裝的dict以獲取該值。

d[2, 5] = 4 
print d[5, 2] 
+0

我想過,但值可能是非常複雜的結構,所以元組永遠是第一要素極爲冗餘(因爲(v1,v2)和(v1,v3)將有v1的兩個副本,如果我沒有引入一個新的結構來存儲指向所有v的指針......)我認爲這使得它相當不雅觀。 – 2010-12-06 16:16:53

+0

也許我會去那個版本,如果另一個是如此困難...我必須重寫哪個成員函數來排序[]運算符中給出的元組,然後將其保存到父代字典中? – 2010-12-06 16:25:58

+0

您必須重寫`__getitem __()`,`__setitem __()`和_ _delitem __()`方法。 http://docs.python.org/reference/datamodel.html#object.__getitem__ – 2010-12-06 16:29:43

1

一個明顯的替代方法是使用一個(v1,v2)元組作爲密鑰到一個單一的標準dict,並插入兩個(v1,v2)(v2,v1)到字典,使得它們指代相同的對象在右手側。

11

你可以使用一個frozenset爲您的字典的關鍵是:

>>> s_d = {} 
>>> s_d[frozenset([5,2])] = 4 
>>> s_d[frozenset([2,5])] 
4 

這將是相當簡單的寫的dict一個子類,把iterables關鍵參數,然後轉身然後進入一個frozenset存儲值時, :

class SymDict(dict): 
    def __getitem__(self, key): 
     return dict.__getitem__(self, frozenset(key)) 

    def __setitem__(self, key, value): 
     dict.__setitem__(self, frozenset(key), value) 

它給你:

>>> s_d = SymDict() 
>>> s_d[5,2] = 4 
>>> s_d[2,5] 
4 
2

正如替代戴夫·韋伯的frozenset,爲什麼不做一個SymDict如下所示:

class SymDict(dict): 
    def __getitem__(self, key): 
     return dict.__getitem__(self, key if key[0] < key[1] else (key[1],key[0])) 

    def __setitem__(self, key, value): 
     dict.__setitem__(self, key if key[0] < key[1] else (key[1],key[0]), value) 

從一個簡單的測試,這是用於獲取和設置項比使用frozenset速度超過10%。無論如何,只是另一個想法。但是,它的適應性不如凍結集,因爲它實際上只能用於長度爲2的元組。據我從OP可以看出,這似乎並不是一個問題。

2

提高對賈斯汀·皮爾的解決方案,你需要添加__delitem____contains__方法幾個字典操作工作。所以,完整性,

class SymDict(dict): 
    def __getitem__(self, key): 
     return dict.__getitem__(self, key if key[0] < key[1] else (key[1],key[0])) 

    def __setitem__(self, key, value): 
     dict.__setitem__(self, key if key[0] < key[1] else (key[1],key[0]), value) 

    def __delitem__(self, key): 
     return dict.__delitem__(self, key if key[0] < key[1] else (key[1],key[0])) 

    def __contains__(self, key): 
     return dict.__contains__(self, key if key[0] < key[1] else (key[1],key[0])) 

所以後來

>>> s_d = SymDict() 
>>> s_d[2,5] = 4 
>>> s_d[5,2] 
4 
>>> (5,2) in s_d 
True 
>>> del s_d[5,2] 
>>> s_d 
{} 

我不知道,不過,是否涵蓋所有的基礎,但它是爲我自己的代碼不夠好。

1

我想提取功能更可讀性(對於patvarilly答案)

class SymDict(dict): 
def __getitem__(self, key): 
    return dict.__getitem__(self, self.symm(key)) 

def __setitem__(self, key, value): 
    dict.__setitem__(self, self.symm(key), value) 

def __delitem__(self, key): 
    return dict.__delitem__(self, self.symm(key)) 

def __contains__(self, key): 
    return dict.__contains__(self, self.symm(key)) 


@staticmethod 
def symm(key): 
    return key if key[0] < key[1] else (key[1], key[0]). 
相關問題