11

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.

4 Answers 4

13

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
Sign up to request clarification or add additional context in comments.

2 Comments

jsbueno thank you very much. I feel a bit ashamed for not thinking that. Thanks again!
I actually wanted a loop within a loop and your last example was perfect. thanks again.
9

Its better not to reinvent things which are already available. Use filter functions and lambda in these cases. Its more pythonic and looks cleaner.

filter(lambda x:x not in ['b','c'],['a','b','c','d','e'])

alternatively you can use list comprehension

[x for x in ['a','b','c','d','e'] if x not in ['b','c']]

2 Comments

Actually, the list comprehension in your second example is "more Pythonic" than the filter and lambda combination.
thanks but I needed to put one such loop into an other and this way things can become really messy.
3

This is exactly what itertools.ifilter is designed for.

from itertools import ifilter

ifilter(lambda x: x not in ['b', 'c'], ['a', 'b', 'c', 'd', 'e'])

will give you back a generator for your list. If you actually need a list, you can create it using one of the standard techniques for converting a generator to a list:

list(ifilter(lambda x: x not in ['b', 'c'], ['a', 'b', 'c', 'd', 'e']))

or

[x for x in ifilter(lambda x: x not in ['b', 'c'], ['a', 'b', 'c', 'd', 'e'])]

Comments

1

If you are ok with creating a copy of the list you can do it like this (list comprehension):

[s for s in list if s != 'b' and s != 'c']

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.