adamUpchurch
adamUpchurch

Reputation: 121

Iterating over list but some values are skipped...?

Iterating a list to delete values less than target

I am trying to iterate numList and delete all values less than 8 (target). Both 2 & 5 are removed correctly but 3 & 7 are not.

numList = [2, 3, 5, 7, 11, 13, 17, 19]
for n in numList:
    print('Testing: {}'.format(n))
    if n < 8:
        print('-----REMOVING: {}'.format(n))
        numList.remove(n)

EXPECTED RESULTS:
Testing: 2
-----REMOVING: 2
Testing: 3
-----REMOVING: 3
Testing: 5
-----REMOVING: 5
Testing: 7
-----REMOVING: 7
Testing: 11
Testing: 13
Testing: 17
Testing: 19
Expecting: [11, 13, 17, 19]


ACTUAL RESULTS
Testing: 2
-----REMOVING: 2
Testing: 5
-----REMOVING: 5
Testing: 11
Testing: 13
Testing: 17
Testing: 19
Actual: [3, 7, 11, 13, 17, 19]

Upvotes: 2

Views: 111

Answers (3)

Starman
Starman

Reputation: 356

Explanation

Python starts by making a list of indices to loop through, and then looping like a for loop in C, but you are removing items from the list while it's looping.

There are 8 items in your list to start, so imagine python internally decides it's going to loop 8 times, and each time it will access element "i" in your list.

[2, 3, 5, 7, 11, 13, 17, 19]

First it accesses the first element (which is 2). Then you remove 2, so the list now looks like

[3, 5, 7, 11, 13, 17, 19]

Now it accesses the second element (which is 5).

When you wrote the code, you may have expected that the second element would always be considered "3" as it looped through.

Solution

There are a few ways you could handle this. One way that is nice from a python perspective is to use a list comprehension syntax:

numList = [n for n in numList if n >= 8]

If you wanted to, you don't have to overwrite numList here, you could instead assign the right side of the equals sign to a new list name.

Upvotes: 1

Mike M&#252;ller
Mike M&#252;ller

Reputation: 85492

Never change the size of list you iterate over. Better make a new list:

>>> numList = [2, 3, 5, 7, 11, 13, 17, 19]
>>> [x for x in numList if x >= 8]
[11, 13, 17, 19]

Upvotes: 0

Joe Iddon
Joe Iddon

Reputation: 20434

This is because you are removing from a list that you are iterating over.

You need to make a copy of the list first then iterate through that:

numList = [2, 3, 5, 7, 11, 13, 17, 19]
for n in numList[:]:
    print('Testing: {}'.format(n))
    if n < 8:
        print('-----REMOVING: {}'.format(n))
        numList.remove(n)

which gives:

Testing: 2
-----REMOVING: 2
Testing: 3
-----REMOVING: 3
Testing: 5
-----REMOVING: 5
Testing: 7
-----REMOVING: 7
Testing: 11
Testing: 13
Testing: 17
Testing: 19

Note that it is more Pythonic to use a list-comprehension:

numList = [n for n in numList if n >= 8]

which gives:

[11, 13, 17, 19]

Upvotes: 1

Related Questions