我有一个可用的标识符,用于将内容放入字典中:
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
我有一个节点类型,为了散列和相等的目的封装了标识符:
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),但我可以看到存储我的节点的字典。我还可以为节点添加一个额外的字典标识符,但这会很麻烦(我需要包装图类并重写所有添加节点,删除节点,从列表中添加节点,从列表中删除节点,添加边缘等等。键入函数以使该字典保持最新状态。)
这是一个难题。任何帮助都会非常感激!
答案 0 :(得分:5)
而不是
d[n1] = 'Node 1'
使用:
d[n1] = ('Node 1', n1)
无论您如何找到值,都可以访问n1。
如果您拥有的是k2等于k1,我不相信字典可以检索原始密钥k1。
答案 1 :(得分: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]
答案 2 :(得分: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'}
您当然可以定义一个使这更简单的功能:
def get_node(G,n):
return G.node[Node(1)]['obj']
n=get_node(G,1)
print n.properties
答案 3 :(得分:0)
问题是,没有保证密钥实际上是一个节点。怎么办
d[my_id]=d[my_id]
除了现在,所有内容仍然可以完美运行,您的密钥是标识符,而不是节点。 允许两个类“相等”这样是非常危险的。 如果你真的需要找到一个Node的名字,应该在Node类或externaly中完成,但不应该依赖于hash中不存在节点。
如果你不能修改它(因为你不能修改代码),那么我猜你是坚持做无效的方式
答案 4 :(得分:0)
使用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
...