2

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.

  • It is definitely the remove method. If numList.remove(n) commented out, the program print statements run correctly.
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]

adamUpchurch
  • 111
  • 1
  • 1
  • 5
  • 3
    Possible duplicate of [Remove items from a list while iterating](https://stackoverflow.com/questions/1207406/remove-items-from-a-list-while-iterating) – thebjorn Dec 11 '17 at 19:30

3 Answers3

1

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]
Joe Iddon
  • 20,101
  • 7
  • 33
  • 54
1

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.

Starman
  • 336
  • 2
  • 11
0

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]
Mike Müller
  • 82,630
  • 20
  • 166
  • 161