Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

how to correctly modify the iterator of a loop in python from within the loop

what I basically need is to check every element of a list and if some criteria fit I want to remove it from the list.

So for example let's say that

list=['a','b','c','d','e']

I basically want to write (in principle and not the actual code I try to implement)

If an element of the list is 'b' or 'c' remove it from the list and take the next.

But

for s in list:
    if s=='b' or s=='c':
        list.remove(s)

fails because when 'b' is removed the loop takes 'd' and not 'c' as the next element. So is there a way to do that faster than storing the elements in a separate list and removing them afterwards?

Thanks.

like image 621
tst Avatar asked Dec 17 '11 11:12

tst


People also ask

How do you change iterable in Python?

Python iter() is an inbuilt function that is used to convert an iterable to an iterator. It offers another way to iterate the container i.e access its elements. iter() uses next() for obtaining values. The iter() method returns the iterator for the provided object.

Can I modify list while iterating?

The general rule of thumb is that you don't modify a collection/array/list while iterating over it. Use a secondary list to store the items you want to act upon and execute that logic in a loop after your initial loop.

How do you write a for loop in Python using iterator?

It uses the next() method for iteration. next ( __next__ in Python 3) The next method returns the next value for the iterable. When we use a for loop to traverse any iterable object, internally it uses the iter() method to get an iterator object which further uses next() method to iterate over.

Can you modify for loops?

You can modify the loop variable in a for loop, the problem is that for loops in Python are not like "old-style" for loops in e.g. Java, but more like "new-style" for-each loops.


1 Answers

The easier way is to use a copy of the list - it can be done with a slice that extends "from the beginning" to the "end" of the list, like this:

for s in list[:]:
    if s=='b' or s=='c':
        list.remove(s)

You have considered this, and this is simple enough to be in your code, unless this list is really big, and in a critical part of the code (like, in the main loop of an action game). In that case, I sometimes use the following idiom:

to_remove = []
for index, s in enumerate(list):
    if s == "b" or s == "c":
         to_remove.append(index)

for index in reversed(to_remove):
    del list[index]

Of course you can resort to a while loop instead:

index = 0
while index < len(list):
   if s == "b" or s == "c":
       del list[index]
       continue
   index += 1
like image 125
jsbueno Avatar answered Sep 24 '22 06:09

jsbueno