Python list.remove()跳过列表中的下一个元素

时间:2013-01-10 21:37:14

标签: python

Python,但不是编程,新手在这里。我正在使用列表进行编程,并遇到了一个有趣的问题。

width = 2
height = 2

# Traverse the board
def traverse(x, y):
    # The four possible directions
    squares = [(x - 1, y), (x + 1, y), (x, y - 1), (x, y + 1)]
    print squares

    # Remove impossible squares
    for square in squares:
        print "now accessing", square
        if (square[0] < 1 or square[0] > width or 
            square[1] < 1 or square[1] > height or
            square == (1, height)):
            squares.remove(square)
            print "removed", square
    print(squares)

# Testing traverse
traverse(1,1)

这导致以下输出:

[(0, 1), (2, 1), (1, 0), (1, 2)]
now accessing (0, 1)
removed (0, 1)
now accessing (1, 0)
removed (1, 0)
[(2, 1), (1, 2)]

它完全跳过元素(2,1)和(1,2) - 甚至没有检查它们!我在这里找到了答案,说我不应该在遍历它时修改列表,并且是的,这绝对有意义。菜鸟错了。但有人可以告诉我为什么它不起作用? Python列表背后隐藏着什么?

6 个答案:

答案 0 :(得分:14)

语句for square in squares只是按顺序访问列表中的每个项目:squares[0],然后是squares[1],然后是squares[2],依此类推,直到广告用完为止。

删除squares[0]会将列表中的所有其他项目移至左侧一个广告位;原始squares[1]现在是squares[0],因此for循环将跳过它。

答案 1 :(得分:9)

其他人已经解释过你不应该从正在迭代的数组中删除元素;但是,如果向后遍历数组,则没有问题。

解决此问题的最紧凑方法(假设您在完成后不需要原始数组的副本)是使用reversed()函数,如

for square in reversed(squares)

这将从数组的末尾开始迭代,然后向后工作。以这种方式取出元素不会影响代码的其余部分,因为您不会更改尚未访问的元素的顺序。我认为这是解决这个问题最优雅的方法。我学会了这个技巧here

答案 2 :(得分:1)

您正在迭代它时从列表中删除。这不是一个好主意 还有其他方法可以执行您正在尝试的操作,其中一种方法是跟踪要从列表中删除的所有项目的列表索引,然后将其从for-loop中删除

答案 3 :(得分:0)

当您在Python中访问列表并删除元素时,列表会变短。 简单示例:取列表1,2,3,4,5,并删除素数&gt; 1.
如果你看第二个元素(2)并决定删除它,你最终会得到一个1,3,4,5的列表 现在你看第三个元素(你已经看过第二个元素了),你发现它是4.那不是素数,所以你去第五个元素 - 5.删除它。
结果:你有1,3,4,5。 如果你是从数组的另一端开始的,那么事情就可以了。 有意义吗?

编辑: 我在下面创建了另一个答案 - 其他海报对问题的解释比我在这里给出的更好,但我认为我有一个更优雅的解决方案。

答案 4 :(得分:0)

不建议在for循环中删除数组元素,因为for循环按顺序检查索引,而在循环中删除元素则将进行中的元素向左移一个索引,如果要这样做,则使用reversed()

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

对于ele反向(arr): 健康)状况: arr.remove(ele)

答案 5 :(得分:-1)

不要修改您正在迭代的列表!

相反,做一些事情:

for square in squares[:]:

这样你就可以在更改原始内容的同时迭代列表的副本。