如何在python字典中检查冗余组合

时间:2013-08-07 20:39:38

标签: python dictionary

我有以下python字典,其中包含键和值的元组:

{(A, 1): (B, 2),
 (C, 3): (D, 4),
 (B, 2): (A, 1),
 (D, 4): (C, 3),
 }

如何在键和值之间获得一组独特的组合?这样(A,1):(B,2)出现,而不是(B,2):(A,1)

4 个答案:

答案 0 :(得分:7)

d = {('A', 1): ('B', 2),
     ('C', 3): ('D', 4),
     ('B', 2): ('A', 1),
     ('D', 4): ('C', 3),
    }

>>> dict(set(frozenset(item) for item in d.items()))
{('A', 1): ('B', 2), ('D', 4): ('C', 3)}

这通过将字典中的每个键/值对转换为一组来实现。这很重要,因为对于任何(a, b)对,set([a, b])等于set([b, a])。那么,如果我们能够获取所有这些键/值集并将它们添加到集合中,那将是完美的,这将消除所有重复项。我们无法使用set类型执行此操作,因为它不可清除,因此我们使用frozenset代替。内置的dict()函数可以接受任何可迭代的键/值对作为参数,因此我们可以传入我们的键/值对集合,它将按预期工作。

关于此问题的评论中提出了一个很好的观点,如果有任何问题映射到自身会导致问题,例如,如果您有d[('A', 1)] = ('A', 1),要解决此问题,您可以按照评论中的建议使用sorted()

d = {('A', 1): ('A', 1),
     ('C', 3): ('D', 4),
     ('D', 4): ('C', 3),
    }

>>> dict(sorted(item) for item in d.items())
{('A', 1): ('A', 1), ('C', 3): ('D', 4)}

这样做的好处是,对于任何重复项,排序顺序将始终为您提供“较小”的元素作为键,将“较大”作为值。

但是在Python 3.x上,如果你的键和值可能有不同的类型,你需要小心,因为sorted()将引发异常,除非iterable中的所有元素都是相同的类型: / p>

>>> d = {1: 'A', 'A': 1}
>>> dict(sorted(item) for item in d.items())
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 1, in <genexpr>
TypeError: unorderable types: int() < str()

答案 1 :(得分:0)

这是一种手动方式:

res = {}
seen = set()
for key, val in d.items():
    if (val, key) in seen: #no need to check (key, val) since keys are unique
        continue
    res[key] = val
    seen.add((key, val))

答案 2 :(得分:0)

使用set和dict-comprehension:

>>> dic = {('A', 1): ('B', 2), ('C', 3): ('D', 4), ('B', 2): ('A', 1), ('D', 4): ('C', 3)}
>>> seen = set()
>>> { k:v for k,v in dic.items() if (v,k) not in seen and not seen.add((k, v))}
{('A', 1): ('B', 2), ('C', 3): ('D', 4)}

这适用于自映射键值对:

>>> d = {('A', 1): ('A', 1), ('C', 3): ('D', 4), ('D', 4): ('C', 3)}
>>> seen = set()
>>> { k:v for k,v in d.items() if (v,k) not in seen and not seen.add((k, v))}
{('A', 1): ('A', 1), ('D', 4): ('C', 3)}

以上代码相当于:

seen = set()
new_dic = {}
for k,v in dic.items():
    if v, k not in seen:
        new_dic[k] = v
        seen.add((k, v))

答案 3 :(得分:0)

另一种选择:

original_dict = {('A', 1): ('B', 2),
('C', 3): ('D', 4),
('B', 2): ('A', 1),
('D', 4): ('C', 3),
}

new_dict = {}
for a in original_dict.items():
    if a[0] > a[1]:
        one, two = a[1],a[0]
    else:
        one,two = a[0],a[1]
    new_dict[one] = two