Python list.remove () skips the next item in a list

Python, but not programming, new to here. I program lists and run into an interesting problem.

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) 

The result is the following:

 [(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)] 

It completely skips elements (2,1) and (1,2) - without even checking them! I found the answers here, saying that I should not change the list by looking at it, and yup, it definitely makes sense. Beginners mistake. But can anyone tell me WHY this is not working? What is the veil of Python lists?

+6
source share
5 answers

The for square in squares statement simply visits each item in the list in the following order: squares[0] , then squares[1] , then squares[2] and so on, until the square ends.

Removing squares[0] shifts all other elements in the list by one slot; the original squares[1] now squares[0] , so the for loop will skip it.

+12
source

Others have explained that you should not remove elements from the array you are repeating; however, if you move the array back, there is no problem.

The most compact way to solve this problem (provided that you do not need a copy of the original array after completion) is to use the reversed() function, as in

for square in reversed(squares)

This will start at the end of the array and will work backward. Highlighting elements in this way will not affect the rest of the code, since you do not change the order of elements that you have not visited. I think this is the most elegant way to solve this problem. I learned this trick here

+7
source

You remove from the list, iterate over it. This is not a good idea. There are other ways to do what you are trying to do, one of which is keeping track of the list indices of all the items you want to remove from the list, and then remove them outside the for-loop.

+1
source

When you access the list in Python and delete the item, the list becomes shorter. A simple example: take the list 1,2,3,4,5 and delete the prime numbers> 1.
If you look at the second element (2) and decide to delete it, you will get a list that will be 1,3,4,5 Now you look at the third element (you already looked at the second) and you will find it 4. This is not easy , so you go to the fifth element - 5. Remove it. Result: you have 1,3,4,5. If you started from the other end of the array, everything will work fine. It makes sense?

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

0
source

Do not change the lists you repeat!

Instead, do something like:

 for square in squares[:]: 

so that you repeat a copy of the list when you change the original.

0
source

All Articles