2010-11-19 48 views
5

我有把事情在字典中的哈希的標識符:在python中,如何從字典中檢索密鑰?

class identifier(): 
    def __init__(self, d): 
     self.my_dict = d 
     self.my_frozenset = frozenset(d.items()) 
    def __getitem__(self, item): 
     return self.my_dict[item] 
    def __hash__(self): 
     return hash(self.my_frozenset) 
    def __eq__(self, rhs): 
     return self.my_frozenset == rhs.my_frozenset 
    def __ne__(self, rhs): 
     return not self == rhs 

我有一個封裝IDENTIFER的散列和平等的目的節點類型:

class node: 
    def __init__(self, id, value): 
     # id is of type identifier 
     self.id = id 
     self.value = value 
     # define other data here... 
    def __hash__(self): 
     return hash(self.id) 
    def __eq__(self, rhs): 
     if isinstance(rhs, node): 
      return self.id == rhs.id 
     ### for the case when rhs is an identifier; this allows dictionary 
     ### node lookup of a key without wrapping it in a node 
     return self.id == rhs 
    def __ne__(self, rhs): 
     return not self == rhs 

我把一些節點到字典中:

d = {} 
n1 = node(identifier({'name':'Bob'}), value=1) 
n2 = node(identifier({'name':'Alex'}), value=2) 
n3 = node(identifier({'name':'Alex', 'nationality':'Japanese'}), value=3) 
d[n1] = 'Node 1' 
d[n2] = 'Node 2' 
d[n3] = 'Node 3' 

一段時間後,我只有一個標識:

my_id = identifier({'name':'Alex'}) 

有沒有什麼方法可以有效地查找在這個字典中使用這個標識符存儲的節點?

請注意,這比聽起來有點棘手;我知道我可以簡單地使用d[my_id]來檢索關聯的項目'Node 2',但是我想高效地返回對n2的引用。

我知道我可以通過查看d中的每個元素來做到這一點,但我已經嘗試過了,但速度太慢了(字典中有數千個項目,而且我做了相當數量的項目)。

我知道內部dict使用hasheq運營商該標識符存儲節點n2及其相關聯的項目,'Node 2'。實際上,使用my_id來查找'Node 2'實際上需要查找n2作爲中間步驟,所以這絕對應該是可能的。

我正在使用它將數據存儲在圖中。節點有很多額外的數據(我把它放在value),這些數據在散列中沒有使用。我沒有創建我正在使用的圖形包(networkX),但是我可以看到存儲節點的字典。我還可以爲節點添加一個額外的標識符字典,但這會很痛苦(我需要包裝圖類並重寫所有添加節點,刪除節點,從列表中添加節點,從列表中刪除節點,添加邊緣等等鍵入函數以保持字典是最新的)。

這是相當難題。任何幫助將非常感激!

+1

在以後的版本其實也保持「節點屬性」,你可能能夠使用一個內部字典。嘗試G.add_node(id,name ='Bob',value = 2),然後檢查G.node [id]。 – Aric 2010-11-19 14:48:13

+0

+1好評。我使用它來存儲我正在使用的額外事物,但是更改爲更面向對象的設計,因爲有所有'節點'類型應該具有的方法和成員;它不僅僅是「價值」。我在'node'內存儲了很多東西。 – user 2010-11-19 19:51:57

回答

5

而不是

d[n1] = 'Node 1' 

使用:

d[n1] = ('Node 1', n1) 

然後,你必須獲得N1無論你怎麼找到的值。

我不相信如果你所有的字典是k2等於k1,那麼字典就沒有辦法檢索到原始密鑰k1。

+0

感謝您的想法。不幸的是,我無法訪問字典的設置方式 - 在networkX中,此字典實際上存儲了圖中與此節點相鄰的節點列表。但我知道字典必須在內部查找'n2'才能查找''節點2'!如果我不能以這種方式查找'n2',那將會非常令人失望。 – user 2010-11-19 12:40:59

+0

我將此標記爲答案,因爲這是一種有效的解決方法。但基本上,我試圖做的事情不可能完成。就字典而言,如果'hash'是相同的'=='是'True',則即使某些底層數據不同,對象也是相等的。從本質上講,在這種情況下(在字典發現它們相同但含有一些不同的未加數據的情況下)檢索確切的對象是我的糟糕的設計。 :) – user 2012-03-27 21:42:28

3

有兩個字典。 - 每當您向主詞典中添加鍵/值時,還將它們添加到反向詞典中,但鍵/值已交換。

例如:

# When adding a value: 
d[n2] = value; 
# Must also add to the reverse dictionary: 
rev[value] = d 

# This means that: 
value = d[n2] 
# Will be able to efficiently find out the key used with: 
key = rev[value] 
+0

+1但更好,把它抽象成一個類。 – aaronasterling 2010-11-19 12:40:12

+0

不用說,aaronasterling。 :) – Arafangion 2010-11-19 12:41:57

+0

這是一個好主意,如果圖庫是我的代碼,我會建立一些基本上可以做到的事情。但由於它不是,我必須將它包裝在一個必須模擬每個add_node,remove_node,add_list_of_nodes,remove_list_of_nodes,add_egde的類中......這是可行的,但由於必須在內部查找'n2',所以這似乎很不幸。檢索「節點2」。 – user 2010-11-19 12:47:17

0

的事情是,我們無法保證,關鍵是一個有效的節點。如果你做

d[my_id]=d[my_id] 

一切仍然會很好地工作,除了現在,你的關鍵是一個標識符,而不是一個節點。 允許兩個班級像這樣「平等」是非常危險的。 如果你確實需要通過它的名字來找到一個節點,這個名字應該在Node類或者externaly中完成,但是不應該依賴於散列中沒有節點的存在。

如果您不能修改(因爲你不能修改代碼),那麼我想你被卡住使用添加my_id查找「節點2」做ineffecient方式

0

實際需要查找n2作爲中間步驟

這是不是真的。字典是一個散列表:它將項目的散列映射到(一桶)條目。當你要求d[my_id]時,Python首先獲得hash(my_id),然後在d中查找。你很困惑,因爲你有那個hash(n1) == hash(id1),這是一件非常糟糕的事情。

您正在詢問標識符和節點之間的映射。如果你想要其中之一,你將不得不自己創建一個。


標識符在創建時是否都與節點相匹配,或者以後是否構建它們?也就是說,你真的要求能夠找到標識爲identifier({'name':'Alex'})的節點,還是已經創建了該標識並將其添加到節點?如果是後者,您可以執行以下操作:

class Node: 
    def __init__(self, id, value): 
     id.parent = self 
     ... 
+0

1你錯了。散列值必須相等,但相同的散列值不足以查找散列表中的項目。我剛剛重新編寫了'identifier'類,以便它的散列函數總是返回'1'和代碼。這被稱爲碰撞。衝突可能會降低性能,但是在發生衝突時哈希表可以正常工作。這就是爲什麼'dict'需要'hash'和'eq'才能正常工作的原因。請參閱http://en.wikipedia.org/wiki/Hash_table#Collision_resolution。 – user 2010-11-19 19:38:48

+0

Typo--「和問題」 - >「中的代碼以及問題中的代碼可以將兩個密鑰與相同的散列關聯到不同的項目。」 – user 2010-11-19 19:47:13

1

以下是使用NetworkX自定義節點對象的方法。 如果將對象存儲在「節點屬性」字典 中,則可以將其用作反向字典,以通過引用該ID來取回 對象。這有點尷尬 但它的工作原理。

import networkx as nx 

class Node(object): 

    def __init__(self,id,**attr): 
     self.id=id 
     self.properties={} 
     self.properties.update(attr) 

    def __hash__(self): 
     return self.id 

    def __eq__(self,other): 
     return self.id==other.id 

    def __repr__(self): 
     return str(self.id) 

    def __str__(self): 
     return str(self.id) 


G=nx.Graph() 
# add two nodes 
n1=Node(1,color='red') # the node id must be hashable 
n2=Node(2,color='green') 
G.add_node(n1,obj=n1) 
G.add_node(n2,obj=n2) 

# check what we have 
print G.nodes() # 1,2 
print n1,n1.properties['color'] # 1,red 
print n1==n2 # False 
for n in G: 
    print n.properties['color'] 
print Node(1) in G # True 
# change color of node 1 
n1.properties['color']='blue' 
for n in G: 
    print n.properties 

# use "node attribute" data in NetworkX to retrieve object 
n=G.node[Node(1)]['obj'] 
print type(n) # <class '__main__.Node'> 
print n # 1 
print n.id # 1 
print n.properties # {'color': 'blue'} 

當然,你可以定義一個函數,使這個簡單的:NetworkX的

def get_node(G,n): 
     return G.node[Node(1)]['obj'] 

    n=get_node(G,1) 
    print n.properties 
相關問題