1

Executing the following sample code to remove elements from list:

l = ['A', 'B', 'C', 'D']

for x in l:
    print(x, l)
    if x == 'A' or x == 'B':
        l.remove(x)

print(l)

The output in both Python 2.x and Python 3.x is:

$ python3 test.py                                                                                      
A ['A', 'B', 'C', 'D']
C ['B', 'C', 'D']
D ['B', 'C', 'D']
['B', 'C', 'D']

The expected output should be:

['C', 'D']

Why is Python behaving this way ? What is the safest way to remove elements from a list ?

3asm_
  • 133
  • 6
  • You are jumping over an element. –  Aug 22 '16 at 15:22
  • See [this answer](http://stackoverflow.com/a/34238688/4014959) of the linked duplicate, which quotes the official explanation from the Python docs of why you can't remove list items safely this way. – PM 2Ring Aug 22 '16 at 15:34
  • My question is about understanding the unexpected behavior. I don't see this in the first link. – 3asm_ Aug 22 '16 at 15:48

1 Answers1

1

The problem is that when you have deleted 'A', 'B' becomes you first element, and i is "pointing" on the second, which is C. Thus, the check is launched for C and you skipped the check for 'B'

To do what you meant to do, you want to write the following:

a = ['A', 'B', 'C', 'D']

i = 0
while i < len(a):
    if a[i] == 'A' or a[i] == 'B':
        del a[i]
    else:
        i += 1

print(a)

This way if you delete the element your loop is currently looking at, you are looking at the element with the same number, which is the right element to look at after you delete it and element shift. I.e.:

a b c d
  ^
(deleted)
a c d
  ^

On the other hand, if you do not remove the current element, you just proceed to the next one

That is not the optimal way to delete all occurrences of 'A' or 'B' in Python though

Dmitry Torba
  • 3,004
  • 1
  • 14
  • 24