在蟒蛇,你怎么能检索字典的关键?
-
26-09-2019 - |
题
我有用于使事情在字典中可哈希标识符
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
使用hash
和eq
运营商该标识符存储节点n2
及其相关联的项目,'Node 2'
。事实上,使用my_id
实际查找'Node 2'
需要查找n2
作为中间步骤,所以的这个绝对应该是可能的。强>
我用这将数据存储在一个曲线图。该节点有很多的附加数据(这里我把value
)未在哈希使用。我没有创造我使用(networkX)图为包,但我可以看到字典,我的店的节点。我还可以保持一个额外的词典标识周围的节点,但是这将是一个痛苦(我需要包裹图类和重写所有添加节点,删除节点,从列表中添加从列表中的节点,删除节点,增加边缘等类型的功能,以保持该字典最新)。
<强>这是相当了这个难题。任何帮助将非常感激!
解决方案
代替
d[n1] = 'Node 1'
使用:
d[n1] = ('Node 1', n1)
然后你有机会获得N1无论你怎么找到的值。
我不相信有使用词典的方式来找回原来的关键k1如果你所有的是K2等于K1。
其他提示
有两个字典。 - 无论何时一个键/值添加到初级词典,也将它们添加到反向字典,但与换键/值
例如:
# 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]
下面是使用具有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'}
可以当然定义一个函数,使这个简单的:
def get_node(G,n):
return G.node[Node(1)]['obj']
n=get_node(G,1)
print n.properties
的事情是,没有保证,关键是一个有效的节点。如果您
d[my_id]=d[my_id]
一切仍然会很好地工作,现在除外,你的关键是一个标识符,而不是一个节点。 允许两个班为“平等”这样是非常危险的。 如果你真的需要通过它的名字应该在Node类或externaly做才能找到一个节点,但在哈希不应该依赖的不是节点的存在。
如果您不能修改(因为你不能修改代码),那么我想你被卡住做ineffecient方式
使用添加my_id到查找“节点2”实际上需要查找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
...