How to remove an item from a python list if the condition is True?

Possible duplicate:
Remove items from a list iterating in Python

I am trying to remove an item from a list in python:

x = ["ok", "jj", "uy", "poooo", "fren"] for item in x: if len(item) != 2: print "length of %s is: %s" %(item, len(item)) x.remove(item) 

But it does not remove the "fren" element. Any ideas?

+43
python list
Nov 29 2018-11-11T00:
source share
5 answers

You cannot remove items from a list, iterating over it. It is much easier to build a new list based on the old one:

 y = [s for s in x if len(s) == 2] 
+68
Nov 29 '11 at 2:55 a.m.
source share

hymloth and sven respond to work, but they do not change the list (create a new one). If you need to modify the object, you need to assign a slice:

 x[:] = [value for value in x if len(value)==2] 

However, for large lists in which you need to remove multiple items, this is memory consumed, but it works in O (n).

glglgl answer suffers from O (n²) complexity because list.remove is O (n).

Depending on the structure of your data, you may prefer to mark the indices of the elements to be deleted and use del to delete by index:

 to_remove = [i for i, val in enumerate(x) if len(val)==2] for index in reversed(to_remove): # start at the end to avoid recomputing offsets del x[index] 

Now del x[i] also O (n), because you need to copy all the elements after index i (the list is a vector), so you will need to test this against your data. However, this should be faster than using remove , because you do not pay the cost of the search phase for removal, and the cost of copying is the same in both cases.

[edit] A very good version in place, O (n) with limited memory requirements, courtesy of @Sven Marnach . It uses itertools.compress , which was introduced in python 2.7:

 from itertools import compress selectors = (len(s) == 2 for s in x) for i, s in enumerate(compress(x, selectors)): # enumerate elements of length 2 x[i] = s # move found element to beginning of the list, without resizing del x[i+1:] # trim the end of the list 
+34
Nov 29 '11 at 3:11
source share
 x = [i for i in x if len(i)==2] 
+3
Nov 29 '11 at 2:56 a.m.
source share

This is due to the fact that during a deletion, iteration skips one element, since it only works for the index.

Workaround may be:

 x = ["ok", "jj", "uy", "poooo", "fren"] for item in x[:]: # make a copy of x if len(item) != 2: print "length of %s is: %s" %(item, len(item)) x.remove(item) 
+1
Nov 29 '11 at 2:56 a.m.
source share

The already mentioned approach to understanding the list is probably the best choice. But if you absolutely want to do this in place (for example, if x really large), here is one way:

 x = ["ok", "jj", "uy", "poooo", "fren"] index=0 while index < len(x): if len(x[index]) != 2: print "length of %s is: %s" %(x[index], len(x[index])) del x[index] continue index+=1 
+1
Nov 29 '11 at 3:19
source share



All Articles