Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Strange result when removing item from a list while iterating over it

Tags:

python

loops

list

I've got this piece of code:

numbers = range(1, 50)  for i in numbers:     if i < 20:         numbers.remove(i)  print(numbers) 

but the result I'm getting is:
[2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49]

Of course, I'm expecting the numbers below 20 to not appear in the results. Looks like I'm doing something wrong with the remove.

like image 274
Finger twist Avatar asked Jun 07 '11 02:06

Finger twist


People also ask

How do you remove an element from a list in a while loop?

If you want to delete elements from a list while iterating, use a while-loop so you can alter the current index and end index after each deletion.

How do you remove an item from a list in a while loop in Python?

We can delete multiple elements from a list while iterating, but we need to make sure that we are not invalidating the iterator. So either we need to create a copy of the list for iteration and then delete elements from the original list, or we can use the list comprehension or filter() function to do the same.


1 Answers

You're modifying the list while you iterate over it. That means that the first time through the loop, i == 1, so 1 is removed from the list. Then the for loop goes to the second item in the list, which is not 2, but 3! Then that's removed from the list, and then the for loop goes on to the third item in the list, which is now 5. And so on. Perhaps it's easier to visualize like so, with a ^ pointing to the value of i:

[1, 2, 3, 4, 5, 6...]  ^ 

That's the state of the list initially; then 1 is removed and the loop goes to the second item in the list:

[2, 3, 4, 5, 6...]     ^ [2, 4, 5, 6...]        ^ 

And so on.

There's no good way to alter a list's length while iterating over it. The best you can do is something like this:

numbers = [n for n in numbers if n >= 20] 

or this, for in-place alteration (the thing in parens is a generator expression, which is implicitly converted into a tuple before slice-assignment):

numbers[:] = (n for in in numbers if n >= 20) 

If you want to perform an operation on n before removing it, one trick you could try is this:

for i, n in enumerate(numbers):     if n < 20 :         print("do something")         numbers[i] = None numbers = [n for n in numbers if n is not None] 
like image 80
senderle Avatar answered Sep 21 '22 12:09

senderle