比较字典中的元组列表

时间:2016-09-01 09:17:30

标签: python dictionary

我一直在解决这个问题...我有一个简化的数据集,如:     dict = {'A': [('a', 1, 1), ('b', 2, 2), ('c', 3, 3)], 'B': [('b', 2, 2), ('a', 1, 1)], 'C': [('d', 4, 4)], 'D': [('c', 3, 3), ('e', 5, 5)]}
其中值表示元组列表。

我需要找到字典中的每个值,是否是在另一个值中找到的列表元素?如果是,则应从字典中删除键值对。例如,[(' b',2,2),(' a',1,1)]可以在[(' a',1, 1),(' b',2,2),(' c',3,3)],因此' B'的关键值对应该删除。最终字典应如下所示:

dict = {'A': [('a', 1, 1), ('b', 2, 2), ('c', 3, 3)], 'C': [('d', 4, 4)], 'D': [('c', 3, 3), ('e', 5, 5)]}

我搜索了论坛,但没有找到解决这个问题的方法...非常感谢任何帮助!谢谢!

编辑:

此字典不包含重复值,因为我之前通过根据另一组条件映射到另一个字典来删除它们。但是,如果解决方案也可以扩展到重复项,则可能对其他人有用,例如保留所有重复项中的1个。
PS:感谢所有回复!

3 个答案:

答案 0 :(得分:0)

您可以使用sets检查一个值是否包含在一起(set.issubset(otherset))。 以下代码演示了如何轻松实现此功能。对于每个值,检查每个其他值是否包含在内。这可以肯定地进行优化。

# input data
d = {'A': [('a', 1, 1), ('b', 2, 2), ('c', 3, 3)], 'B': [('b', 2, 2), ('a', 1, 1)], 'C': [('d', 4, 4)]}

# convert each value to a set
ds = { k: frozenset(v) for k,v in d.items() }
# filter out contained values
keys = [ k1 for k1,v1 in ds.items() if [k2 for k2,v2 in ds.items() if v1.issubset(v2)] == [k1] ]
# map filtered keys to original dict
df = dict(zip(keys, map(d.get, keys)))
# df = {'A': [('a', 1, 1), ('b', 2, 2), ('c', 3, 3)], 'C': [('d', 4, 4)]}

解释

为每对keys计算(k1,v1)时,完成以下操作。 所有其他对(k2,v2)(包括(k1,v1))都会针对v1.issubset(v2)进行检查。对于满足此条件的所有对,记录密钥(k2)并将其存储在列表中。如果其他值没有包含我们的给定值v1,则此列表将仅包含k1,因为issubset关系是自反的(v.issubset(v)总是True)。因此,当返回的列表正好是[k1]时,我们没问题。 如果列表包含的值多于k1,则v1包含在某个其他值中,必须进行过滤。

重复值

没有为地图中的重复值定义问题。我的解决方案跟踪原始密钥,因此对于重复值,两个对都被丢弃。您还可以在此处介绍自定义行为,例如只保留最小的'所有重复的关键。

其他解决方案保留所有对,因此返回的映射仍包含重复值。

keys的修改版本可以处理上述情况:

keys = [ k1 for k1,v1 in ds.items()
            if not any(v1 < v2 for v2 in ds.values())
               and k1 == min(k2 for k2,v2 in ds.items() if v1 == v2) ]

答案 1 :(得分:0)

您可以将值转换为frozensets集,然后过滤掉重复项,最后选择值在集合中的字典项:

d = {
    'A': [('a', 1, 1), ('b', 2, 2), ('c', 3, 3)],
    'B': [('b', 2, 2), ('a', 1, 1)],
    'C': [('d', 4, 4)]
}

sets = {frozenset(v) for v in d.values()}
sets = {s for s in sets if not any(s < s2 for s2 in sets)}
res = {k: v for k, v in d.items() if set(v) in sets} # {'A': [('a', 1, 1), ('b', 2, 2), ('c', 3, 3)], 'C': [('d', 4, 4)]}

答案 2 :(得分:0)

使用setcombinations

from itertools import combinations

d = {'A': [('a', 1, 1), ('b', 2, 2), ('c', 3, 3)], 'B': [('b', 2, 2), ('a', 1, 1)], 'C': [('d', 4, 4)]}

xs = set()

for (ai, av), (bi, bv) in combinations(d.items(), 2):
    if set(av) <= set(bv): xs.add(ai)
    if set(bv) <= set(av): xs.add(bi)

for x in xs: del d[x]
print d
# {'A': [('a', 1, 1), ('b', 2, 2), ('c', 3, 3)], 'C': [('d', 4, 4)]}