How to delete an item in a list if it exists?
--
Music by Eric Matyas
https://www.soundimage.org
Track title: Popsicle Puzzles
--
Chapters
00:00 Question
01:32 Accepted answer (Score 921)
06:53 Answer 2 (Score 13)
07:12 Answer 3 (Score 12)
07:27 Answer 4 (Score 9)
07:55 Thank you
--
Full question
https://stackoverflow.com/questions/4915...
Accepted answer links:
[Duck-typed]: http://docs.python.org/glossary.html#ter...
[EAFP]: http://docs.python.org/glossary.html#ter...
[PEP 463]: http://www.python.org/dev/peps/pep-0463/
[contextlib's suppress() contextmanager]: https://docs.python.org/3/library/contex...
[Lisp]: https://en.wikipedia.org/wiki/Lisp_%28pr...
[Guido was even talking about dropping ]: http://www.artima.com/weblogs/viewpost.j...
[functools]: http://docs.python.org/2/library/functoo...
[high order functions]: http://en.wikipedia.org/wiki/Higher-orde...
[List comprehensions]: http://en.wikipedia.org/wiki/List_compre...
[PEP 202]: http://www.python.org/dev/peps/pep-0202/
[PEP 289]: http://www.python.org/dev/peps/pep-0289/
[lazy evaluated]: http://en.wikipedia.org/wiki/Lazy_evalua...
[this Python history blog]: http://python-history.blogspot.com.br/20...
[GvR]: http://en.wikipedia.org/wiki/Guido_van_R...
[set-builder notation]: http://en.wikipedia.org/wiki/Set-builder...
[set]: http://www.python.org/dev/peps/pep-3100/...
[dict comprehensions]: http://www.python.org/dev/peps/pep-0274/
[the difference is important]: https://stackoverflow.com/q/2209755/
--
Content licensed under CC BY-SA
https://meta.stackexchange.com/help/lice...
--
Tags
#python #list
#avk47
ACCEPTED ANSWER
Score 956
1) Almost-English style:
Test for presence using the in operator, then apply the remove method.
if thing in some_list: some_list.remove(thing)
The removemethod will remove only the first occurrence of thing, in order to remove all occurrences you can use while instead of if.
while thing in some_list: some_list.remove(thing)
- Simple enough, probably my choice.for small lists (can't resist one-liners)
2) Duck-typed, EAFP style:
This shoot-first-ask-questions-last attitude is common in Python. Instead of testing in advance if the object is suitable, just carry out the operation and catch relevant Exceptions:
try:
some_list.remove(thing)
except ValueError:
pass # or scream: thing not in some_list!
except AttributeError:
call_security("some_list not quacking like a list!")
Off course the second except clause in the example above is not only of questionable humor but totally unnecessary (the point was to illustrate duck-typing for people not familiar with the concept).
If you expect multiple occurrences of thing:
while True:
try:
some_list.remove(thing)
except ValueError:
break
- a little verbose for this specific use case, but very idiomatic in Python.
- this performs better than #1
- PEP 463 proposed a shorter syntax for try/except simple usage that would be handy here, but it was not approved.
However, with contextlib's suppress() contextmanager (introduced in python 3.4) the above code can be simplified to this:
with suppress(ValueError, AttributeError):
some_list.remove(thing)
Again, if you expect multiple occurrences of thing:
with suppress(ValueError):
while True:
some_list.remove(thing)
3) Functional style:
Around 1993, Python got lambda, reduce(), filter() and map(), courtesy of a Lisp hacker who missed them and submitted working patches*. You can use filter to remove elements from the list:
is_not_thing = lambda x: x is not thing
cleaned_list = filter(is_not_thing, some_list)
There is a shortcut that may be useful for your case: if you want to filter out empty items (in fact items where bool(item) == False, like None, zero, empty strings or other empty collections), you can pass None as the first argument:
cleaned_list = filter(None, some_list)
- [update]: in Python 2.x,
filter(function, iterable)used to be equivalent to[item for item in iterable if function(item)](or[item for item in iterable if item]if the first argument isNone); in Python 3.x, it is now equivalent to(item for item in iterable if function(item)). The subtle difference is that filter used to return a list, now it works like a generator expression - this is OK if you are only iterating over the cleaned list and discarding it, but if you really need a list, you have to enclose thefilter()call with thelist()constructor. - *These Lispy flavored constructs are considered a little alien in Python. Around 2005, Guido was even talking about dropping
filter- along with companionsmapandreduce(they are not gone yet butreducewas moved into the functools module, which is worth a look if you like high order functions).
4) Mathematical style:
List comprehensions became the preferred style for list manipulation in Python since introduced in version 2.0 by PEP 202. The rationale behind it is that List comprehensions provide a more concise way to create lists in situations where map() and filter() and/or nested loops would currently be used.
cleaned_list = [ x for x in some_list if x is not thing ]
Generator expressions were introduced in version 2.4 by PEP 289. A generator expression is better for situations where you don't really need (or want) to have a full list created in memory - like when you just want to iterate over the elements one at a time. If you are only iterating over the list, you can think of a generator expression as a lazy evaluated list comprehension:
for item in (x for x in some_list if x is not thing):
do_your_thing_with(item)
- See this Python history blog post by GvR.
- This syntax is inspired by the set-builder notation in math.
- Python 3 has also set and dict comprehensions.
Notes
- you may want to use the inequality operator
!=instead ofis not(the difference is important) - for critics of methods implying a list copy: contrary to popular belief, generator expressions are not always more efficient than list comprehensions - please profile before complaining
ANSWER 2
Score 13
try:
s.remove("")
except ValueError:
print "new_tag_list has no empty string"
Note that this will only remove one instance of the empty string from your list (as your code would have, too). Can your list contain more than one?
ANSWER 3
Score 10
If index doesn't find the searched string, it throws the ValueError you're seeing. Either
catch the ValueError:
try:
i = s.index("")
del s[i]
except ValueError:
print "new_tag_list has no empty string"
or use find, which returns -1 in that case.
i = s.find("")
if i >= 0:
del s[i]
else:
print "new_tag_list has no empty string"
ANSWER 4
Score 7
Adding this answer for completeness, though it's only usable under certain conditions.
If you have very large lists, removing from the end of the list avoids CPython internals having to memmove, for situations where you can re-order the list. It gives a performance gain to remove from the end of the list, since it won't need to memmove every item after the one your removing - back one step (1).
For one-off removals the performance difference may be acceptable, but if you have a large list and need to remove many items - you will likely notice a performance hit.
Although admittedly, in these cases, doing a full list search is likely to be a performance bottleneck too, unless items are mostly at the front of the list.
This method can be used for more efficient removal,
as long as re-ordering the list is acceptable. (2)
def remove_unordered(ls, item):
i = ls.index(item)
ls[-1], ls[i] = ls[i], ls[-1]
ls.pop()
You may want to avoid raising an error when the item isn't in the list.
def remove_unordered_test(ls, item):
try:
i = ls.index(item)
except ValueError:
return False
ls[-1], ls[i] = ls[i], ls[-1]
ls.pop()
return True
- While I tested this with CPython, its quite likely most/all other Python implementations use an array to store lists internally. So unless they use a sophisticated data structure designed for efficient list re-sizing, they likely have the same performance characteristic.
A simple way to test this, compare the speed difference from removing from the front of the list with removing the last element:
python -m timeit 'a = [0] * 100000' 'while a: a.remove(0)'With:
python -m timeit 'a = [0] * 100000' 'while a: a.pop()'(gives an order of magnitude speed difference where the second example is faster with CPython and PyPy).
- In this case you might consider using a
set, especially if the list isn't meant to store duplicates.
In practice though you may need to store mutable data which can't be added to aset. Also check on btree's if the data can be ordered.