Deleting a List Item While Iterating

Let’s trim a long list and list the list.

list_1 = [1, 2, 3, 4]
list_2 = [1, 2, 3, 4]
list_3 = [1, 2, 3, 4]
list_4 = [1, 2, 3, 4]
for idx, item in enumerate(list_1):
del item
for idx, item in enumerate(list_2):
list_2.remove(item)
for idx, item in enumerate(list_3[:]):
list_3.remove(item)
for idx, item in enumerate(list_4):
list_4.pop(idx)
print(list_1)
print(list_2)
print(list_3)
print(list_4)

Can you guess why the output is [2, 4]?

Explanation

  • It’s never a good idea to change the object that you’re iterating over. The correct way to do so is to iterate over a copy of the object instead, and list_3[:] does just that.
some_list = [1, 2, 3, 4]
print(id(some_list))
print(id(some_list[:])) # Notice that python creates new object for sliced list.

The difference between del, remove, and pop:

  • del var_name just removes the binding of the var_name from the local or global namespace (that’s why the list_1 is unaffected).
  • remove removes the first matching value, not a specific index, and raises ValueError if the value is not found.
  • pop removes the element at a specific index and returns it, and raises IndexError if an invalid index is specified.

Why is the output [2, 4]?

  • The list iteration is done index by index, and when we remove 1 from list_2 or list_4, the contents of the lists are now [2, 3, 4]. The remaining elements are shifted down, i.e., 2 is at index 0, and 3 is at index 1. Since the next iteration is going to look at index 1 (which is the 3), the 2 gets skipped entirely. A similar thing will happen with every alternate element in the list sequence.
  • Refer to this StackOverflow thread explaining the example.
  • See also this nice StackOverflow thread for a similar example related to dictionaries in Python.