As you have discovered, attempting to remove elements from a list that you are iterating over may not do what you expect. Ashwani Agarwal's answer illustrates why it fails, and the other answers show various techniques that can be used to perform the removals correctly. Another technique that can be useful when you have a very large list that you can't afford to copy is to iterate over it in reverse:
my_list = ['a', 'b', 'c', 'a', 'b', 'c', 'a']
for element in reversed(my_list):
if 'a' not in element:
my_list.remove(element)
print(element, my_list)
print('Final:', my_list)
my_list = ['a', 'b', 'c', 'a', 'b', 'c', 'a']
for element in reversed(my_list):
if 'a' in element:
my_list.remove(element)
print(my_list)
print('Final:', my_list)
output
c ['a', 'b', 'a', 'b', 'c', 'a']
c ['a', 'b', 'a', 'b', 'a']
b ['a', 'a', 'b', 'a']
b ['a', 'a', 'a']
Final: ['a', 'a', 'a']
['b', 'c', 'a', 'b', 'c', 'a']
['b', 'c', 'b', 'c', 'a']
['b', 'c', 'b', 'c']
Final: ['b', 'c', 'b', 'c']
This code uses the reversed()
function, which returns an iterator over the iterable you pass to it; it doesn't copy the iterable.
I should mention that this technique is less efficient than the filtering approaches given in other answers. That's because each call of my_list.remove(element)
has to scan through my_list
until it finds a matching element, so it has complexity O(n**2) where n
is the number of elements in the list; the filtering algorithms have a complexity of O(n). So as I said earlier, this approach is only useful when the list is so large that you can't afford the RAM to create a new list.
Another thing I need to mention about the code in your question: you are using a list comprehension to loop over a list when you should be using plain for
loop. list.remove()
returns None
, so your code is needlessly creating a list full of None
s and then throwing that list away. The general rule is: don't use a list comprehension purely for the side effects of a function you call in it.