如何在 Python 的 for 循环中删除列表元素? [复制]

Posted

技术标签:

【中文标题】如何在 Python 的 for 循环中删除列表元素? [复制]【英文标题】:How to remove list elements in a for loop in Python? [duplicate] 【发布时间】:2012-05-26 19:02:02 【问题描述】:

我有一个清单

a = ["a", "b", "c", "d", "e"]

我想在下面的 for 循环中删除此列表中的元素:

for item in a:
    print(item)
    a.remove(item)

但它不起作用。我能做什么?

【问题讨论】:

为什么要同时删除?只需遍历然后删除整个列表。另外,您真的需要打印每个项目吗? 但是当我遍历循环时,我依赖于列表中的项目。如果它符合条件,我必须立即摆脱它 【参考方案1】:

在使用for 循环迭代列表时,不允许从列表中删除元素。

重写代码的最佳方法取决于您要执行的操作。

例如,您的代码相当于:

for item in a:
    print(item)
a[:] = []

或者,您可以使用while 循环:

while a:
    print(a.pop(0))

我正在尝试删除符合条件的项目。然后我转到下一项。

您可以将不匹配条件的每个元素复制到第二个列表中:

result = []
for item in a:
    if condition is False:
        result.append(item)
a = result

或者,您可以使用filter 或列表解析并将结果分配回a

a = filter(lambda item:... , a)

a = [item for item in a if ...]

其中... 代表您需要检查的条件。

【讨论】:

我正在尝试删除符合条件的项目。然后我转到下一项。 “你不被允许”——当然可以。 Python 不会抱怨你,它只是给出了与人们期望的稍微(阅读:完全)不同的结果。 为什么?有人可以指出为什么会这样吗?该列表在每次迭代中都会重新评估,对吗?那么有什么问题呢? 问题是python保留了一个内部计数器来记住当前的elelement,当列表从迭代器下发生变化时,它将引用一些意想不到的东西。 (但在删除时从后向前迭代可能会按预期工作?) 使用.pop(0)效率非常低!它的时间复杂度为 O(N)。只需使用时间复杂度 O(1) 的pop()【参考方案2】:

遍历列表的副本:

>>> a = ["a", "b", "c", "d", "e"]
>>> for item in a[:]:
    print(item)
    if item == "b":
        a.remove(item)

a
b
c
d
e
>>> print(a)
['a', 'c', 'd', 'e']

【讨论】:

这个和 OP 方法的一个问题是,如果有多个比较相等的元素,它们可能会崩溃。 太棒了!这个对我有用! @NPE 我想这取决于你期望发生什么。如果您希望代码删除列表中的所有“b”实例,那么它不应该中断,因为list.remove 只删除了一项。 大列表的内存问题? @aggregate116​​6877 好问题!在这种情况下,如果我们不遍历副本,那么删除“b”将使itemb 跳到d - 所以如果我们想删除“b”或“c”,那么它会失败。快速解释:gist.github.com/alexlouden/9f1ab4354d1c68ae4c1c94126ac51a20【参考方案3】:

正如其他答案所说,最好的方法是创建一个新列表 - 遍历副本,或者构建一个仅包含您想要的元素的列表并将其分配回同一个变量。这些之间的区别取决于您的用例,因为它们会以不同的方式影响原始列表的其他变量(或者,更确切地说,第一个会影响它们,而第二个不会)。

如果由于某种原因无法选择副本,您确实有另一个选择,该选择依赖于理解为什么修改您正在迭代的列表会中断。列表迭代通过跟踪索引来工作,每次在循环中递增它,直到它掉出列表的末尾。因此,如果您在当前索引处(或之前)删除,则从该点到结尾的所有内容都会向左移动一个位置。但是迭代器不知道这一点,并且有效地跳过了下一个元素,因为它现在位于 current 索引而不是下一个。但是,删除当前索引 之后的内容不会影响任何内容。

这意味着,如果您将列表迭代到前面,如果您删除当前索引处的项目,则它右侧的所有内容都会向左移动 - 但这并不重要,因为您已经处理了所有要当前位置的右侧,并且您正在向左移动 - 左侧的下一个元素不受更改的影响,因此迭代器为您提供了您期望的元素。

TL;DR:

>>> a = list(range(5))
>>> for b in reversed(a):
    if b == 3:
        a.remove(b)
>>> a
[0, 1, 2, 4]

但是,就使代码易于阅读而言,制作副本通常更好。为了完整起见,我只提到这种可能性。

【讨论】:

【参考方案4】:
import copy

a = ["a", "b", "c", "d", "e"]

b = copy.copy(a)

for item in a:
    print(item)
    b.remove(item)
a = copy.copy(b)

工作:为避免更改您正在迭代的列表,您复制a,对其进行迭代并从b 中删除项目。然后将b(更改后的副本)复制回a

【讨论】:

等等,所以 .remove(...) 可以从“b”中删除实例,即使从技术上讲,传递的实例是“a”的实例?【参考方案5】:

如何创建一个新列表并将您想要的元素添加到该新列表中。遍历列表时不能删除元素

【讨论】:

【参考方案6】:

回答这个问题可能有点晚了,但我刚刚找到了这个帖子,并且我之前已经为它创建了自己的代码......

    list = [1,2,3,4,5]
    deleteList = []
    processNo = 0
    for item in list:
        if condition:
            print(item)
            deleteList.insert(0, processNo)
        processNo += 1

    if len(deleteList) > 0:
        for item in deleteList:
            del list[item]

这可能是一个很长的路要走,但似乎运作良好。我创建了第二个列表,其中仅包含与要删除的列表项相关的数字。请注意,“插入”在位置 0 处插入列表项编号并将其余部分推入,因此在删除项时,列表将从最高编号删除回最低编号,因此列表保持顺序。

【讨论】:

以上是关于如何在 Python 的 for 循环中删除列表元素? [复制]的主要内容,如果未能解决你的问题,请参考以下文章

在 Python 中使用 for 循环计算元组列表的平均值

问题在for循环中删除列表项(python)[重复]

Python列表元组字典集合存储结构

python中for循环删除不全的问题

[Python3]循环控制

Python——用for循环删除列表中的元素