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

Posted on

Solving problem is about exposing yourself to as many situations as possible like Strange result when removing item from a list while iterating over it and practice these strategies over and over. With time, it becomes second nature and a natural way you approach any problems in general. Big or small, always start with a plan, use other strategies mentioned here till you are confident and ready to code the solution.
In this post, my aim is to share an overview the topic about Strange result when removing item from a list while iterating over it, which can be followed any time. Take easy to follow this discuss.

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

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.

Answer #1:

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]
Answered By: senderle

Answer #2:

@senderle’s answer is the way to go!

Having said that to further illustrate even a bit more your problem, if you think about it, you will always want to remove the index 0 twenty times:

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

So you could actually go with something like this:

aList = range(50)
i = 0
while i < 20:
    aList.pop(0)
    i += 1
print(aList) #[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]

I hope it helps.


The ones below are not bad practices AFAIK.

EDIT (Some more):

lis = range(50)
lis = lis[20:]

Will do the job also.

EDIT2 (I’m bored):

functional = filter(lambda x: x> 20, range(50))
Answered By: Trufa

Answer #3:

Removing items from a list is simple: begin at the list’s end:

li = range(1,15)
print li,'n'
for i in xrange(len(li)-1,-1,-1):
    if li[i] < 6:
        del li[i]
print li

result

[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14]
[6, 7, 8, 9, 10, 11, 12, 13, 14]
Answered By: eyquem

Answer #4:

So I found a solution but it’s really clumsy…

First of all you make an index array, where you list all the index’ you want to delete like in the following

numbers = range(1, 50)
index_arr = []
for i in range(len(numbers):
    if numbers[i] < 20:
        index_arr.append(i)

after that you want to delete all the entries from the numbers list with the index saved in the index_arr. The problem you will encounter is the same as before. Therefore you have to subtract 1 from every index in the index_arr after you just removed a number from the numbers arr, like in the following:

numbers = range(1, 50)
index_arr = []
for i in range(len(numbers):
    if numbers[i] < 20:
        index_arr.append(i)
for del_index in index_list:
    numbers.pop(del_index)
    #the nasty part
    for i in range(len(index_list)):
        index_list[i] -= 1

It will work, but I guess it’s not the intended way to do it

Answered By: Yassin Julian
The answers/resolutions are collected from stackoverflow, are licensed under cc by-sa 2.5 , cc by-sa 3.0 and cc by-sa 4.0 .

Leave a Reply

Your email address will not be published. Required fields are marked *