避免将重复项插入 Python 具有理解力的列表
Avoid inserting duplicates into Python list with 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))
来解决这个问题,但我想了解我的代码有什么问题。
问题是在您完成理解之前 keys_shared_values
是空的,因此您的 k1 not in keys_shared_values
将始终 return 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]
您的代码无法运行,因为 key_shared_values
未定义。如果你清理你的环境,你会发现如果你尝试 运行 你的例子你会得到一个 NameError: name 'key_shared_values' is not defined
错误。
这是因为 keys_shared_values
直到理解语句 运行s 才真正定义,你不能在理解中真正引用它,因为它还不存在。
如果您要预定义它,例如 keys_shared_values = []
那么这仍然行不通,因为每次您在理解中引用它时,它都会引用原始的空列表值。执行理解时,它不会动态更改 keys_shared_values
的值,而是在内存中创建列表,然后将其分配给 keys_shared_values
.
其他人已经解释了你的列表理解有什么问题。这是另一种方法,使用 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]
请注意,这也更有效,因为您比较字典中两个项目的每个组合,得到二次复杂度,而这种方法具有线性复杂度。
我有字典:
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))
来解决这个问题,但我想了解我的代码有什么问题。
问题是在您完成理解之前 keys_shared_values
是空的,因此您的 k1 not in keys_shared_values
将始终 return 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]
您的代码无法运行,因为 key_shared_values
未定义。如果你清理你的环境,你会发现如果你尝试 运行 你的例子你会得到一个 NameError: name 'key_shared_values' is not defined
错误。
这是因为 keys_shared_values
直到理解语句 运行s 才真正定义,你不能在理解中真正引用它,因为它还不存在。
如果您要预定义它,例如 keys_shared_values = []
那么这仍然行不通,因为每次您在理解中引用它时,它都会引用原始的空列表值。执行理解时,它不会动态更改 keys_shared_values
的值,而是在内存中创建列表,然后将其分配给 keys_shared_values
.
其他人已经解释了你的列表理解有什么问题。这是另一种方法,使用 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]
请注意,这也更有效,因为您比较字典中两个项目的每个组合,得到二次复杂度,而这种方法具有线性复杂度。