14

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 列表的面纱背后是什么?

4

6 回答 6

18

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

解决这个问题的最简洁的方法(假设你完成后不需要原始数组的副本)是使用reversed()函数,如

for square in reversed(squares)

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

于 2013-01-11T17:25:22.677 回答
16

该语句for square in squares只是按顺序访问列表中的每个项目:squares[0],然后squares[1],然后squares[2],等等,直到它用完正方形。

删除squares[0]将列表中的所有其他项目移到左侧一个插槽;原来squares[1]是 now squares[0],所以 for 循环会跳过它。

于 2013-01-10T21:39:41.130 回答
2

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

于 2013-01-10T21:39:33.477 回答
1

When you are accessing a list in Python and remove an element, the list becomes shorter. Simple example: take the list 1,2,3,4,5, and remove the prime numbers > 1.
If you look at the second element (2) and decide to remove it, you end up with a list that goes 1,3,4,5 Now you look at the third element (you have already looked at the second one), and you find it's 4. That's not prime, so you go to the fifth element - 5. Remove it.
Result: you have 1,3,4,5. If you had started from the other end of the array, things would work just fine. Make sense?

EDIT: I have created another answer below - other posters gave a better explanation of the problem than I gave here, but I think I have a more elegant solution.

于 2013-01-10T21:42:27.780 回答
1

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

相反,请执行以下操作:

for square in squares[:]:

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

于 2013-01-10T21:58:40.733 回答
0

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

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

for ele in reversed(arr): 条件:arr.remove(ele)

于 2020-09-09T17:09:42.223 回答