tags:

views:

322

answers:

5

Hi I am looking for a way to remove a sublist from a list. something like this:

a=range(1,10)  
a.remove([2,3,7])  
print a  
a=[1,4,5,6,8,9]  
+11  A: 
>>> a=range(1,10)
>>> [x for x in a if x not in [2,3,7]]
[1, 4, 5, 6, 8, 9]
S.Mark
+1  A: 
a=range(1,10)
b = filter(lambda x:x not in set([2,3,7]), a)
print b
b = [1, 4, 5, 6, 8, 9]

update:

a=range(1,10)
itemsToRemove = set([2,3,7])
b = filter(lambda x: x not in itemsToRemove, a)

or

b = [x for x in a if x not in itemsToRemove]
Yaroslav
+1 for using sets
dalloliogm
Except it creates N sets, N being len(a).
FogleBird
It creates only one set at the creation of the lambda function
Xavier Combelle
Good point, FogleBird. Need to create it outside of lambda or list comprehension.
Yaroslav
Xavier, FogleBird is right. You can prove it by creating wrapper function of 'set' which counts its calls.
Yaroslav
Using `filter` with an anonymous function is silly. The list comprehension makes a lot more sense in that use case.
Mike Graham
A: 

Others have suggested ways to make newlist after filtering e.g.

newl = [x for x in l if x not in [2,3,7]]

or

newl = filter(lambda x: x not in [2,3,7], l) 

but from your question it looks you want in-place modification for that you can do this, this will also be much much faster if original list is long and items to be removed less

l = range(1,10)
for o in set([2,3,7,11]):
    try:
        l.remove(o)
    except ValueError:
        pass

print l

output: [1, 4, 5, 6, 8, 9]

I am checking for ValueError exception so it works even if items are not in orginal list.

Also if you do not need in-place modification solution by S.Mark is simpler.

Anurag Uniyal
if you really need in-place modification, the previous answers can be modified to: `a[:] = [x for x in a if x not in [2,3,7]]`. This will be faster than your code.
Seth Johnson
yes a[:] can be used, but it not obvious that it will be faster, for long lists with few values to remove my code will be much much faster e.g. try list to remove = [1] :)
Anurag Uniyal
@Anurag: You seem to be right; timing tests make it look like removing in place is faster.
Seth Johnson
What you need to do if you want to use `remove` is loop calling `l.remove` over and over until you get `ValueError` and at that point break that loop. That would account for the case that there are multiple occurrences of a value in the list. (The better solution is still your first one, though.)
Mike Graham
@Seth Johnson, Premature optimization much?
Mike Graham
@Mike: No, but I had hoped that the cleaner (shorter one-line) version would be better. I don't use Python when I want optimized code. I use C++ with SWIG. :)
Seth Johnson
@Seth Johnson, "Better" doesn't mean fastest, especially not when a piece of code isn't proven to be slowing down an application. Criteria like correctness (which the `remove` option does not qualify for), readability, testability, and maintainability are almost always more important.
Mike Graham
+2  A: 

The simplest way is

>>> a=range(1,10)
>>> for x in [2,3,7]:
...  a.remove(x)
... 
>>> a
[1, 4, 5, 6, 8, 9]

One possible problem here is that each time you call remove(), all the items are shuffled down the list to fill the hole. So if a grows very large this will end up being quite slow.

This way builds a brand new list. The advantage is that we avoid all the shuffling of the first approach

>>> removeset = set([2,3,7])
>>> a=[x for x in a if x not in removeset]

If you want to modify a in place, just one small change is required

>>> removeset = set([2,3,7])
>>> a[:]=[x for x in a if x not in removeset]
gnibbler
@gnibbler, Your claim *"So if `a` grows very large this will end up being quite slow."* is a bit misleading. If only the length of `a` is unbounded, all of the snippets you provided are O(n). The **real** problem with `remove` is that it only removes *the first occurrence* of its arguments, not all occurrences. It is also generally more in keeping with writing clear, idiomatic code to make a new list rather than mutating the old one.
Mike Graham
@Mike, I attempted to keep the answer simple as the OP has used the beginner tag.
gnibbler
@gnibbler, "simple" is no excuse for *incorrect*.
Mike Graham
+2  A: 
>>> a=range(1,10)
>>> for i in [2,3,7]: a.remove(i)
...
>>> a
[1, 4, 5, 6, 8, 9]

>>> a=range(1,10)
>>> b=map(a.remove,[2,3,7])
>>> a
[1, 4, 5, 6, 8, 9]
ghostdog74
Don't use `map` for side effects. `map` is for collecting the result of a bunch of calls. For loops are the tool for doing something a bunch of times.
Mike Graham
if what you mean by side effects are those "none" return by `map`, then it can "masked" off. Other than that, its still valid, and i like the conciseness of it.
ghostdog74