Build my own Hello World

It's just a personal note.

In Python, How remove method works while it is used in for loops.

What's this?

If you need to modify the sequence you are iterating over while inside the loop (for example to duplicate selected items), it is recommended that you first make a copy. Iterating over a sequence does not implicitly make a copy. The slice notation makes this especially convenient:

  • I tried checking how the remove method works when it is used in "for loops".

What I learned

What is the problem?

  • As written in the above sentences, if I modify the sequence while inside the loops, I possibly have outputs that are different from what I thought I would have.

  • This is one of the samples that caused the problem.

l = list(range(10))

for i in l:
  if i >= 5:
    l.remove(i)

# I expect [0, 1, 2, 3, 4]
print(l) # => [0, 1, 2, 3, 4, 6, 8]
  • when carefully read the official document again, I can see this note.

  • That is, even if some elements are removed, the internal counter is incremented as usual. That caused the skip of some elements and the above result.

Note There is a subtlety when the sequence is being modified by the loop (this can only occur for mutable sequences, e.g. lists). An internal counter is used to keep track of which item is used next, and this is incremented on each iteration. When this counter has reached the length of the sequence the loop terminates. This means that if the suite deletes the current (or a previous) item from the sequence, the next item will be skipped (since it gets the index of the current item which has already been treated). Likewise, if the suite inserts an item in the sequence before the current item, the current item will be treated again the next time through the loop. This can lead to nasty bugs that can be avoided by making a temporary copy using a slice of the whole sequence, e.g.,

What should I do?

There are some solutions to avoid that.

make a temporary copy

  • This solution is expressed in the official document.
  • Using l[:]makes a copy of the list.
l = list(range(10))

for i in l[:]:
  if i >= 5:
    l.remove(i)

print(l) # => [0, 1, 2, 3, 4]
  • Also, we can use l.copy().
    • When an element of a shallow copy of a list is changed(removed), the original list is not changed if the changed element is immutable.

use list comprehension and filter

  • we can enumerate all the elements we want to remain by using list comprehension and filter, and then build the objective list.
l = list(range(10))
l = [i for i in l if i < 5]

print(l) # => [0, 1, 2, 3, 4]
l = list(range(10))
l = list(filter(lambda i: i < 5, l))

print(l) # => [0, 1, 2, 3, 4]