如何在Python中迭代列表时从其中删除元素?

4

给定一个数字列表:

L = [1, 2, 3, 4, 5]

在迭代列表时,如何删除一个元素(比如3)?

我尝试了以下代码,但没有成功:

for el in L:
    if el == 3:
        del el

这个问题不是很好或者太泛泛了,因为它只询问如何删除第一个匹配特定值的元素,而Python已经有了内置的L.remove(3)或列表推导式。但是这个问题并不能涵盖所有更一般的情况,比如“从排序列表中删除重复相邻的值”。 - smci
这个问题中并不清楚 OP 想要什么。根据意图,任何一个相关的重复问题都可能是合适的。 - Karl Knechtel
2个回答

13

通常最好采取建设性的方式--构建您想要的新项目清单,而不是删除您不需要的项目。例如:

L[:] = [el for el in L if el != 3]

列表推导式构建所需的列表,并将其赋值给“整个列表切片”L [:],确保您不仅重新绑定名称,而是完全替换内容,因此效果与您想要执行的“删除”完全相同。这也很快。
如果您一定要进行删除,可以采用微妙的方法。
>>> ndel = 0
>>> for i, el in enumerate(list(L)):
...    if el==3:
...      del L[i-ndel]
...      ndel += 1

使用循环语句而不是列表推导式的代码不如优雅、简洁、简单或高效,但它确实完成了任务(虽然其正确性不容易一眼看出,事实上,在编辑之前我就弄错了!),“不惜一切代价”适用于此;-)。

对于“必须执行删除”的情况,按索引循环而不是按项循环是另一种较差但可行的方法——但请记住在这种情况下要反转索引...:

for i in reversed(range(len(L))):
  if L[i] == 3: del L[i]

实际上,当我们在辩论是否添加内置函数 reversed 时,这是其主要使用案例之一 -- 没有 reversed,获取 reversed(range(... 并不容易,而倒序遍历列表有时很有用。替代方法是

for i in range(len(L) - 1, -1, -1):

很容易出现错误,哈哈;-)。

不过,随着其他替代方案的考虑,我在这个答案开头推荐的列表解析看起来越来越好了,是吧?-)


好主意。我没有想到。谢谢,Alex! :) - bodacydo
1
第二种方法将在需要删除多个元素时删除错误的元素,因为第一次删除后索引会发生变化。 - interjay
@interjay,+1:你说得对,我进行了编辑以弥补这一点(不幸的是reversed(enumerate(...不起作用——enumerate是一个可迭代对象而不是序列,reversed需要一个序列作为其参数)。 - Alex Martelli

-4
for el in L:
    if el == 2:
        del L[el]

需要枚举才能索引L[idx]。 - Andrew Jaffe
不好,这样做会表现出非常奇怪的方式 - 如果完全不相关的项等于2,则删除L的“第三个项目”(可能不止一次),并且在执行此类删除时经常跳过L中的一个项目。真是个噩梦调试...!-) - Alex Martelli

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