我有一个用值列表制作的字典。其中一些值也是字典中其他键/值对中的键或值。我只想计算字典中有多少这些独特的对。
实施例。
dict = {'dog':['milo','otis','laurel','hardy'],'cat':['bob','joe'],'milo':['otis','laurel','hardy','dog'],'bob':['cat','joe'],'hardy':['dog']}
我需要计算没有在dict中与另一个共享键/值的键/值对的数量。例如,上面应该只计算2,那些连接到狗和猫。尽管milo对于狗来说是独一无二的,但是狗也是'hardy'的关键/值对,因此这两者应该一起计算(即只有1)。 (见下面的评论) 我试图通过用'key B'替换另一个键(键B)的值中存在的键(键A)来实现它,但没有成功,因为我无法正确指定键B.
for keys, values in dict.iteritems():
for key,value in dict.iteriterms():
if key in values:
dict[keys] = dict.pop(key)
有更简单的方法吗? 提前谢谢......
答案 0 :(得分:2)
如果我正确理解了问题,您的词典就是图表的邻接地图,而您正试图找到connected components的集合。常规算法(使用深度或广度优先搜索)可能无法正常工作,因为您的图表不是无向的(例如,您有"bob"
和"cat"
到"joe"
的边缘,但没有来自"joe"
)。
相反,我建议使用disjoint set data structure。使用字典构建一个来处理值到父级的映射并不困难。这是我为前一个问题写的一个实现:
class DisjointSet:
def __init__(self):
self.parent = {}
self.rank = {}
def find(self, element):
if element not in self.parent: # leader elements are not in `parent` dict
return element
leader = self.find(self.parent[element]) # search recursively
self.parent[element] = leader # compress path by saving leader as parent
return leader
def union(self, leader1, leader2):
rank1 = self.rank.get(leader1,0)
rank2 = self.rank.get(leader2,0)
if rank1 > rank2: # union by rank
self.parent[leader2] = leader1
elif rank2 > rank1:
self.parent[leader1] = leader2
else: # ranks are equal
self.parent[leader2] = leader1 # favor leader1 arbitrarily
self.rank[leader1] = rank1+1 # increment rank
以下是您可以用它来解决问题的方法:
djs = DisjointSet()
all_values = set()
for key, values in my_dict.items():
all_values.add(key)
all_values.update(values)
for val in values:
l1 = djs.find(key)
l2 = djs.find(val)
if l1 != l2:
djs.union(l1, l2)
roots = {djs.find(x) for x in all_values}
print("The number of disjoint sets is:", len(roots))
这段代码的第一部分做了两件事。首先,它构建一个集合,其中包含图形中任何位置的所有唯一节点。其次,它通过在任何有边缘的地方进行并集来将节点组合成不相交的集合。
第二步是从不相交的集合中构建一组“根”元素。
答案 1 :(得分:1)
以下是一种可能的解决方案:
values = {'dog':['milo','otis','laurel','hardy'],
'cat':['bob','joe'],
'milo':['otis','laurel','hardy','dog'],
'bob':['cat','joe'],
'hardy':['dog']}
result = []
for x in values.iteritems():
y = set([x[0]] + x[1])
if not any([z for z in result if z.intersection(y)]):
result.append(y)
print len(result)
请注意,您不应该调用变量dict
,因为您要隐藏内置类型dict
。
您的目标不明确,但您可以修改y
set
的构造以满足您的需求。
答案 2 :(得分:0)
如果我正确理解了您的问题,那么您正在尝试描述类似图形的结构,并且您正在查看键是否出现在值列表中。既然你只对count感兴趣,那么在迭代dict时你不必担心将来的值列表,所以这应该有效:
d = {'dog': ['milo','otis','laurel','hardy'],'cat': ['bob','joe'],'milo': 'otis','laurel','hardy','dog'], 'bob': ['cat','joe'], 'hardy': ['dog']}
seen = set()
unique = []
for key, values in d.iteritems():
if key not in seen:
unique.append(key)
seen = seen.union(values)
print(len(unique))
请注意,unique
中包含的实际值取决于字典顺序,只是键,而不是值。如果您实际上尝试进行某种网络或图形分析,我建议您使用networkx