a = [1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89]
b = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13]
new_list = []
new_list.append([num for num in a+b if num not in new_list])
print(new_list)
输出:
[[1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13]]
为什么这段代码会产生重复项,而不是像set()
那样产生一个没有重复项的所有数字的列表?
new_list = [] new_list.append([num for num in a+b if num not in new_list])
有几件事会阻止它工作。
-
将一个列表中的元素添加到另一个列表中,使用
extend
而不是append
。append
将整个列表附加到输入列表中,而不是添加单个元素。 -
即使您将其更改为
extend
,列表推导式中的所有项目在添加到new_list
之前都会生成。它们不会一个接一个地添加,因此not in new_list
检查不会看到以前迭代中的项。它将对空的new_list
进行检查。
这种习惯用法实际上只适用于显式循环。我猜你是这样开始的:
new_list = []
for num in a+b:
if num not in new_list:
new_list.append(num)
这种类型的循环不能很好地转换为列表推导式,因为它具有自我依赖性。循环依赖于之前迭代的结果。
如果使用extend而不是append,使用迭代器而不是列表作为形参,就可以了:
new_list.extend(num for num in a+b if num not in new_list)
通过使用迭代器作为形参,可以随时更新new_list的内容,因此推导式中的条件可以访问到目前为止列表的内容。当你有一个列表作为参数时,在更新new_list之前,整个参数都会被求值,所以new_list在推导过程中保持为空,并且条件永远不会找到之前的元素(尚未添加的元素)
请注意,这是一种跳过重复值的低效方法,因为当列表被填满时,检查现有值所需的时间越来越长,导致时间复杂度为O(n^2)。你应该使用集合而不是列表。
您可以通过使用列表推导来实现,但严格考虑执行它的副作用:
a = [1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89]
b = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13]
new_list = []
[new_list.append(num) for num in a+b if num not in new_list]
print(new_list) # -> [1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 4, 6, 7, 9, 10, 11, 12]
如果您不喜欢构建一个立即被丢弃的列表,这里有一个替代方案,它使用生成器表达式和内置的any()
函数来消费它:
a = [1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89]
b = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13]
new_list = []
any((new_list.append(num) for num in a+b if num not in new_list))
print(new_list) # -> [1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 4, 6, 7, 9, 10, 11, 12]