如何从python中删除defaultdict(int)中的重复值?

时间:2016-11-13 01:52:13

标签: python duplicates defaultdict

我有一个字典,它由唯一的键值对组成,如下所示:

    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})

我想删除这些重复的值。关于这个问题的任何建议都表示赞赏。

3 个答案:

答案 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