如果我在迭代时从列表中删除,为什么会跳过元素?

时间:2015-02-21 05:54:53

标签: python list python-2.7

我试过了:

list = [[1], [2], [], [4], [5], [], [], [], [9]]
for e in list:
    if e == []:
        list.remove(e)

然后我得到了

>>> list
[[1], [2], [4], [5], [], [9]]

发生什么事了?!

2 个答案:

答案 0 :(得分:2)

for e in list:
    if e == []:
        list.remove(e)

在这种情况下,当e为空列表时,将从列表中删除该特定值。因此,列表中的下一个元素将成为当前元素。在下一次迭代中,从列表中获取下一个元素。由于实际的下一个元素已向后移动,因此将采用下一个实际的下一个元素。因此,如果有多个连续匹配,则有可能跳过元素。

在您的情况下,我们可以在e

之后说[]位于[2]
[[1], [2], [], [4], [5], [], [], [], [9]]
            ^

由于它是一个空列表,它将被删除,列表变为

[[1], [2], [4], [5], [], [], [], [9]]
            ^

在下一次迭代中,将选择下一个元素,所以

[[1], [2], [4], [5], [], [], [], [9]]
                 ^

在这种情况下,我们默默跳过[4]。但是,由于预期在产出中,它没有任何区别。但请考虑[]后的[5]

[[1], [2], [4], [5], [], [], [], [9]]
                      ^

这将被删除,所以列表就像这样

[[1], [2], [4], [5], [], [], [9]]
                      ^

现在,在下一次迭代中,e将引用下一个元素,即

[[1], [2], [4], [5], [], [], [9]]
                          ^

因此,删除当前的空列表,[9]成为当前元素。就是这样,跳过其中一个空列表。

注意:最重要的是,在迭代它时,永远不要从容器中删除项目。

解决方案1:

最常见的技术是使用迭代列表的副本进行迭代,并在循环中修改实际列表。例如,

for e in list[:]:       # `list[:]` is a shallow copy of `list`
    if e == []:
        list.remove(e)

解决方案2:(首选方式)

使用列表理解,使用过滤条件创建新列表,如此

>>> [e for e in list if e]
[[1], [2], [4], [5], [9]]

注意消除空列表的方式。 Python中的空列表被视为Falsy值。因此,if e仅在e至少包含一个元素时才会评估为Truthy。

答案 1 :(得分:0)

与语言无关的解决方案:向后迭代

l = [[1], [2], [], [4], [5], [], [], [], [9]]
for e in reversed(l):
    if e == []:
        l.remove(e)