0

i am trying to remove all digits consisting "five" from a list

it works with with >for loop< but not completely, and i am interested why is there such "anomaly" or i did something wrong?

if i use >filter< function, there is no such problem, all "fives" were removed!

the_list = [i for i in range(101)]

for i in the_list:
   if "5" in str(i):
      the_list.remove(i)

print(the_list)

Output:

[0, 1, 2, 3, 4, 6, 7, 8, 9, 10, 11, 
12, 13, 14, 16, 17, 18, 19, 20, 21, 
22, 23, 24, 26, 27, 28, 29, 30, 31, 
32, 33, 34, 36, 37, 38, 39, 40, 41, 
42, 43, 44, 46, 47, 48, 49, 51, 53, 
55, 57, 59, 60, 61, 62, 63, 64, 66, 
67, 68, 69, 70, 71, 72, 73, 74, 76, 
77, 78, 79, 80, 81, 82, 83, 84, 86, 
87, 88, 89, 90, 91, 92, 93, 94, 96, 
97, 98, 99, 100]


Why [51, 53, 55, 57, 59] are still in the list?

Mac
  • 1
  • 1
  • 4
    why not simply construct the list without the 5s? `nums = [i for i in range(101) if '5' not in str(i)]` – Gábor Fekete Jan 06 '23 at 14:34
  • i know, i just was interested why it behaves like that, exactly with for loop. Thank you very much. – Mac Jan 06 '23 at 14:48
  • That's actually mentioned in the official python tutorial: [4.2 `for` statements](https://docs.python.org/3/tutorial/controlflow.html#for-statements). *"Code that modifies a collection while iterating over that same collection can be tricky to get right. Instead, it is usually more straight-forward to loop over a copy of the collection or to create a new collection."* – Stef Jan 06 '23 at 15:18
  • 1
    If you really want to use `list.remove`, you can do `for x in list(the_list): if '5' in str(x): the_list.remove(x)` But note that using `remove` is pretty inefficient as `remove` has to loop through the list to find the elements to remove, so it's a loop inside a loop, resulting in quadratic time complexity. By contrast, `new_list = [x for x in the_list if '5' not in str(x)]` has linear time complexity. – Stef Jan 06 '23 at 15:20

1 Answers1

0

You are amending the_list in real time so in effect the_list changes everytime you delete an item. So i in your loop is no longer the same value as the element stored in the_list[i].

This discrepancy gets worse the further through the loop you go hence the weird results. Make a copy of the_list to iterate through & then delete from the original list, try the following to see what I mean,

import copy

the_list = [i for i in range(101)]
the_list_copy = copy.copy(the_list)

for i in the_list_copy:
    
    print(str(i))
    
    if "5" in str(i):
        the_list.remove(i)

print(the_list)

The copy doesn't get altered to you never get the list index i not equal to the corresponding element.

DrBwts
  • 3,470
  • 6
  • 38
  • 62