避免在理解中将重复项插入到Python列表中

时间:2015-04-08 10:29:15

标签: python python-2.7 dictionary list-comprehension

我有一本字典:

XY_dict = {1: [(12, 55),(13, 55)],
2: [(14, 55),(15, 57)],
3: [(14, 55),(15, 58)],
4: [(14, 55),(16, 55)]}

我想知道哪些键的值元组是唯一的(不会出现在任何其他键的值中)。从示例字典中,密钥1是唯一的,因为(12, 55)(13, 55)都不存在于任何其他字典的密钥中。通过获取具有共享值的键列表,我可以稍后反转结果并获取唯一的键。

我使用列表解析来获取具有共享值的键:

keys_shared_values = [k1 for k1,v1 in XY_dict.iteritems()
                       for k,v in XY_dict.iteritems()
                       for XY_pair in v
                       if XY_pair in v1 and k != k1 and k1 not in keys_shared_values]

结果,我得到[2, 2, 3, 3, 4, 4]但我希望不会插入重复项(因为我正在评估键值是否在结果列表中)。我可以通过运行list(set(shared_values))来解决这个问题,但是想了解我的代码有什么问题。

3 个答案:

答案 0 :(得分:3)

其他人已经解释了列表理解的问题。这是另一种方法,使用Counter字典来计算不同xy对出现的频率,并使用它来过滤字典中的唯一条目。

>>> from collections import Counter
>>> c = Counter(xy for v in XY_dict.values() for xy in v)
>>> {k: v for k, v in XY_dict.iteritems() if all(c[xy] == 1 for xy in v)}
{1: [(12, 55), (13, 55)]}

或者获取具有共享值的键:

>>> [k for k, v in XY_dict.iteritems() if any(c[xy] > 1 for xy in v)]
[2, 3, 4]

请注意,这也更有效,因为您比较字典中的每个两个项的组合,为您提供二次复杂度,而这种方法具有线性复杂性。

答案 1 :(得分:1)

问题是keys_shared_values在您完成理解之前是空的,因此k1 not in keys_shared_values将始终返回True。你不能参考当前的理解。您最好的选择是按照您的建议转换为set

如果您需要该功能,则应将代码更改为循环:

keys_shared_values = []
for k, v in XY_dict.iteritems():
    for k1, v1 in XY_dict.iteritems():
        for XY_pair in v:
            if XY_pair in v1 and k != k1 and k1 not in keys_shared_values:
                keys_shared_values.append(k1)
print keys_shared_values

结果:

[3, 4, 2]

答案 2 :(得分:1)

您的代码无法正常运行,因为未定义key_shared_values。如果您清理环境,您会看到如果您尝试运行示例,则会出现NameError: name 'key_shared_values' is not defined错误。

这是因为keys_shared_values在理解语句运行之前并没有真正定义,你无法在理解中真正引用它,因为它还不存在。

如果您要预定义它,例如keys_shared_values = [],那么这仍然不起作用,因为每次您在理解中引用它时它将引用原始的空列表值。执行理解后,它不会动态更改keys_shared_values的值,而是在内存中创建列表,然后将其分配给keys_shared_values