2010-11-19 52 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 
相关问题