这个 Python 列表删除循环有什么问题?

4

今晚我已经工作了很长时间,编写了一个长程序。但我遇到了一个简单的障碍。有人能告诉我为什么这段代码会按照它的方式工作吗?

我有两个列表。我希望list2只包含不在list1中的数字。从逻辑上讲,这似乎应该起作用。但实际上却没有。为什么呢?

list1 = [1,2,3,4,5,6,7,8]
list2 = [12,15,16,7,34,23,5,23,76,89,9,45,4]


for ch in list2:
    if ch in list1:
         list2.remove(ch)

return list2

一些方法可以返回如下结果: [15,7,5,23,76,9,4]。
为什么会这样呢?
我应该如何实现我需要的功能?
3个回答

9
当您修改正在迭代的序列时,它会产生意想不到的结果。我建议使用这种方法,利用快速的set操作。
list2 = list(set(list2) - set(list1))

无论这种方法是否比使用列表推导式更快还是更慢,取决于 list1 list2 的大小,以及您是否可以将其之一作为初始化的一部分转换为 set 而不是在循环中多次进行转换。

5
不要在迭代列表时修改它。
你想要的可以直接用列表推导式表达:
list2 = [ch for ch in list2 if ch not in list1]

这种方法更易读,与使用集合的解决方案不同的是,它不会从list2中删除重复项或更改项目顺序。

更新:当list1很大时,从中创建一个集合实际上会加快速度:

list2 = [ch for ch in list2 if ch not in set(list1)]

那是一个很好的观点。虽然你可能想把list1转换成set - Michael Hoffman

1

这是一个有趣的观点。让我解释一下为什么会发生这种情况。

在Python中,当你使用for a in list时,Python按顺序查看列表的第1个元素、第2个元素等等。所以它首先查看12并将其删除。然后它查看第2个元素,除了现在15是第1个元素,16是第2个元素。它删除16。因此,15从未被检查,留在列表中。然后它类似地跳过7并删除34...

避免这种情况的方法当然是不要在正在删除元素的同一列表上进行迭代。你可以复制第二个列表。检查这个副本中的成员是否在第一个列表中。如果不是,则从第二个列表中删除它。我相信已经发布的一些建议对你有用。这就是解释。


1
这也是我的想法,但代码不应该删除12,因为它不在list1中。 - David Z

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接