How to remove item from a python list in a loop?

PythonList

Python Problem Overview


> Possible Duplicate:
> Remove items from a list while iterating in Python

I'm 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 doesn't remove "fren" item. Any ideas?

Python Solutions


Solution 1 - Python

You can't remove items from a list while iterating over it. It's much easier to build a new list based on the old one:

y = [s for s in x if len(s) == 2]

Solution 2 - Python

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

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

However, for large lists in which you need to remove few elements, this is memory consuming, but it runs in O(n).

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

Depending on the structure of your data, you may prefer noting the indexes of the elements to remove and using the del keywork to remove 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] is also O(n) because you need to copy all elements after index i (a list is a vector), so you'll need to test this against your data. Still this should be faster than using remove because you don't pay for the cost of the search step of remove, and the copy step cost is the same in both cases.

[edit] Very nice in-place, O(n) version 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

Solution 3 - Python

x = [i for i in x if len(i)==2]

Solution 4 - Python

This stems from the fact that on deletion, the iteration skips one element as it semms only to work on the index.

Workaround could 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)

Solution 5 - Python

The already-mentioned list comprehension approach is probably your best bet. But if you absolutely want to do it in-place (for example if x is really large), here's 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

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionalwbtcView Question on Stackoverflow
Solution 1 - PythonSven MarnachView Answer on Stackoverflow
Solution 2 - Pythongurney alexView Answer on Stackoverflow
Solution 3 - PythonhymlothView Answer on Stackoverflow
Solution 4 - PythonglglglView Answer on Stackoverflow
Solution 5 - PythonAustin MarshallView Answer on Stackoverflow