我有一个字典,它由唯一的键值对组成,如下所示:
edu_bg={1: 1, 2: 2, 3: 1, 4: 1, 5: 2, 6: 2}
我想从上面的数据创建一个字典,以便类似的记录(具有相似的值)按如下方式组合在一起:
{(1, 3): 1, (5, 6): 1, (1, 4): 1, (2, 6): 1,(2, 5): 1, (3, 4): 1})
我尝试使用以下代码实现上述输出:
myedu = defaultdict(int)
for k,v in edu_bg.iteritems():
for K,V in edu_bg.iteritems():
if K == k and V == v:
pass
if K != k and V == v:
myedu[(k,K)] += 1
else:
pass
然而,它导致重复记录如下:
defaultdict(<type 'int'>, {(1, 3): 1, (5, 6): 1, (4, 1): 1, (3, 1): 1, (5, 2): 1, (1, 4): 1, (2, 6): 1, (4, 3): 1, (6, 2): 1, (2, 5): 1, (3, 4): 1, (6, 5): 1})
我想删除这些重复的值。关于这个问题的任何建议都表示赞赏。
答案 0 :(得分:2)
反转映射并获取按其值分区的键组的组合。
>>> edu_bg={1: 1, 2: 2, 3: 1, 4: 1, 5: 2, 6: 2}
>>> def invert(d):
... i={}
... for k,v in d.iteritems():
... i.setdefault(v,[]).append(k)
... return i
...
>>> invert(edu_bg)
{1: [1, 3, 4], 2: [2, 5, 6]}
然后,对于您计算combinations(sublist, 2)
的每个子列表:
>>> [comb for sublist in {1: [1, 3, 4], 2: [2, 5, 6]}.values() for comb in combinations(sublist, 2)]
[(1, 3), (1, 4), (3, 4), (2, 5), (2, 6), (5, 6)]
所有计数始终为1,因为每个组合仅生成一次。 因此,我们可以简单地生成请求的输出:
>>> dict.fromkeys([(1, 3), (1, 4), (3, 4), (2, 5), (2, 6), (5, 6)], 1)
{(2, 6): 1, (5, 6): 1, (1, 4): 1, (1, 3): 1, (2, 5): 1, (3, 4): 1}
每个步骤合并
>>> dict.fromkeys([comb for sublist in invert(edu_bg).values() for comb in combinations(sublist, 2)],1)
{(2, 6): 1, (5, 6): 1, (1, 4): 1, (1, 3): 1, (2, 5): 1, (3, 4): 1}
这比迭代产品或组合和过滤的成本要低得多。这也会生成所有输出而没有重复。
答案 1 :(得分:1)
您可以迭代每个可能的组合,而不是遍历每对的笛卡尔乘积,这将完全迭代n ^ 2个元素,这将迭代n(n-1)/ 2个元素。虽然Big Oh复杂性相同,但恒定因子将显着降低:
>>> from collections import defaultdict
>>> from itertools import combinations
>>> myedu = defaultdict(int)
>>> edu_bg={1: 1, 2: 2, 3: 1, 4: 1, 5: 2, 6: 2}
>>> for k1,k2 in combinations(edu_bg,2):
... if edu_bg[k1] == edu_bg[k2]:
... myedu[(k1,k2)] += 1
...
>>> myedu
defaultdict(<class 'int'>, {(2, 6): 1, (1, 3): 1, (5, 6): 1, (2, 5): 1, (3, 4): 1, (1, 4): 1})
>>>
我应该重申,这听起来像XY problem ......
答案 2 :(得分:0)
您正在将每个键与所有其他键(包括他们自己)进行比较。这些导致n ** 2检查,包括两个你不想考虑的情况:密钥与自身相比,密钥比较两次。你已经正确地传递了密钥相等的情况。您可以传递密钥k
小于密钥K
的情况,这将忽略本应重复的一半检查。
from collections import defaultdict
edu_bg = {1:1, 2:2, 3:1, 4:1, 5:2, 6:2}
myedu = defaultdict(int)
for k,v in edu_bg.iteritems():
for K,V in edu_bg.iteritems():
if K == k and V == v:
pass
if K > k and V == v:
myedu[(k,K)] += 1
else:
pass
print myedu
理想情况下,您会限制for
循环,以便密钥被等同或两次计数的情况永远不会发生。您可以通过以下方式执行此操作:
edu_bg = {1:1, 2:2, 3:1, 4:1, 5:2, 6:2}
myedu = defaultdict(int)
keys = edu_bg.keys()
for i in xrange(len(keys)):
for j in xrange(i+1, len(keys)):
k = keys[i]
K = keys[j]
if edu_bg[k] == edu_bg[K]:
myedu[(k,K)] += 1
print myedu