Python Forum
.remove() method in for-loop - Printable Version

+- Python Forum (https://python-forum.io)
+-- Forum: Python Coding (https://python-forum.io/forum-7.html)
+--- Forum: Homework (https://python-forum.io/forum-9.html)
+--- Thread: .remove() method in for-loop (/thread-13288.html)



.remove() method in for-loop - nzcan - Oct-08-2018

it is clear what this code do:
>>> sw = ['go', 'bo']
>>> for cm in sw:
... 	if cm == 'bo':
... 		sw.remove(cm)
... 
>>> sw 
['go'] 
but when a list contains 4 'bo' items only 2 will be removed:
>>> sw = ['go', 'bo', 'bo', 'bo', 'bo']
>>> for cm in sw:
... 	if cm == 'bo':
... 		sw.remove(cm)
... 
>>> sw 
['go', 'bo', 'bo']
>>>  
why not all 'bo' items are removed?


RE: .remove() method in for-loop - ichabod801 - Oct-08-2018

Because you are changing the list as you are looping over it. When it goes to get the fourth item, there's only three items left. In cases like this you would either loop through a copy of the list (for cm in sw[:]:), or you would use a while loop:

while 'bo' in sw:
    sw.remove('bo')



RE: .remove() method in for-loop - TimeMen - Oct-08-2018

Why not doing like this?
>>> sw = ['go', 'bo', 'bo', 'bo', 'bo']
>>> for i in range(0, sw.count("bo")):
...     sw.remove("bo")
... 
>>> sw
['go']
Well, ichabod was faster and more clever using while-loop


RE: .remove() method in for-loop - ichabod801 - Oct-08-2018

Or you could do a list comprehension:

sw = [item for item in sw if item != 'bo']
For large lists, that would probably be more efficient. Filter might be even more efficient.


RE: .remove() method in for-loop - snippsat - Oct-08-2018

(Oct-08-2018, 08:30 PM)TimeMen Wrote: Why not doing like this?
If think about it's about 8-9 function call for that short list,without running profile on it.

ichabod80 Wrote:Or you could do a list comprehension:
It's about as pythonic as it get.
It work well in most cases small or big list.

I think set() can be fast if have larger list.
>>> sw = ['go', 'bo', 'bo', 'bo', 'bo']
>>> set(sw) - set(['bo'])
{'go'}
Can do some measuring with timeit.
import timeit

def time_1(lst):
    for i in range(0, lst.count("bo")):
        lst.remove("bo")

def time_2(lst):
    sw = [item for item in lst if item != 'bo']

def time_3(lst):
    set(lst) - set(['bo'])

def time_4(lst):
    while 'bo' in lst:
        lst.remove('bo')

lst = ['time_1', 'time_2', 'time_3', 'time_4']
for test in lst:
    t = timeit.Timer(f"{test}(['go', 'bo', 'bo', 'bo', 'bo'])", f'from __main__ import {test}').timeit(number=10000000)
    print(f'{test} --> {t:.2f}')
Output:
time_1 --> 13.59 time_2 --> 7.83 time_3 --> 9.11 time_4 --> 10.88
Now make list bigger *100,and run it a little less average iteration number=100000.
Now see that set() shine 0.87,and list comprehension still okay with 2.16
Output:
time_1 --> 48.71 time_2 --> 2.16 time_3 --> 0.87 time_4 --> 87.82



RE: .remove() method in for-loop - ichabod801 - Oct-09-2018

Yes, but set will change the order and remove duplicates. That may be desired behavior. And you didn't test filter. If you add

def time_5(lst):
    sw = filter(lambda item: item != 'bo', lst)
Then the short list times are:

Output:
time_1 --> 9.78 time_2 --> 4.95 time_3 --> 6.95 time_4 --> 7.73 time_5 --> 3.40
And the long list times are:

Output:
time_1 --> 4.09 time_2 --> 0.18 time_3 --> 0.07 time_4 --> 7.32 time_5 --> 0.03



RE: .remove() method in for-loop - snippsat - Oct-09-2018

(Oct-09-2018, 01:04 AM)ichabod801 Wrote: And you didn't test filter. If you add
Yes the filter one is fast.
Can also do a run PyPy,
It take a lot time down on the solution that not so optimal and not so much(as expected) on solution that is already good.
# Python 3.7
λ python test_bo.py
time_1 --> 53.79
time_2 --> 2.16
time_3 --> 1.03
time_4 --> 92.84
time_5 --> 0.20

# PyPy Python 3.5
λ pypy3 test_bo.py
time_1 --> 17.54
time_2 --> 0.76
time_3 --> 0.93
time_4 --> 21.62
time_5 --> 0.15



RE: .remove() method in for-loop - gruntfutuk - Oct-13-2018

You can avoid a lot of problems when removing items from a list if you traverse it in reverse:

sw = ['bo', 'go', 'bo', 'do', 'bo', 'we', 'bo', 'bo']
for cm in sw[::-1]:
    if cm == "bo":
        sw.remove("bo")
print(sw)
['go', 'do', 'we']