Is there a simple way to delete a list element by value?
Asked Answered
G

27

1201

I want to remove a value from a list if it exists in the list (which it may not).

a = [1, 2, 3, 4]
b = a.index(6)

del a[b]
print(a)

The above gives the error:

ValueError: list.index(x): x not in list

So I have to do this:

a = [1, 2, 3, 4]

try:
    b = a.index(6)
    del a[b]
except:
    pass

print(a)

But is there not a simpler way to do this?

Globulin answered 8/5, 2010 at 7:48 Comment(4)
You calculate the index of 6 in your list. But 6 is not in your list ... so what's supposed to happen? :)Sicard
this has nothing to do with deleting a value in a list, since your code does not reach the del statement. Maybe you should retitle it "how do I get the index of a value that is not in a list. Obvious answer - you can't.Vail
@Dave Well, not really. He wants to delete an item from the list regardless of whether it exists or not, not to get the index for a nonexistent item. The question is well asked.Maraca
Beside the point, but a bare except is bad practice. Use except Exception at a minimum.Mccracken
S
1890

To remove the first occurrence of an element, use list.remove:

>>> xs = ['a', 'b', 'c', 'd']
>>> xs.remove('b')
>>> print(xs)
['a', 'c', 'd']

To remove all occurrences of an element, use a list comprehension:

>>> xs = ['a', 'b', 'c', 'd', 'b', 'b', 'b', 'b']
>>> xs = [x for x in xs if x != 'b']
>>> print(xs)
['a', 'c', 'd']
Sicard answered 8/5, 2010 at 7:56 Comment(9)
Fails if the element is not in the list. :)Maraca
@Maraca list comprehension does not fail even if the element isn't in the list, does it?Verde
To clarify for anyone skimming, it "fails" in the sense that it raises a ValueError exception.Humanoid
The list comprehension change the list reference so if there is a copy of the reference somewhere, the removal will not follow.Original
What is the complexity of remove is it O(n)?Post
I do not imagine why it should be more or less than O(n). I think that it uses an ordinary search algorithm. No additional information about any sorting of the list!Hanover
FWIW, .remove is O(n) to find the item, and O(n) to move the subsequent items down to fill the gap, but both those operations run essentially at C speed.Irrelevance
this answer does not answer the question, as it fails when the element is not in the listCorinthian
Technically, this comprehension does not remove an element. It creates a new list, which might be a problem if the list is an argument to the function or typed as Final. The fix is simple: instead of xs = ..., use xs[:] = ....Grained
J
212

Usually Python will throw an Exception if you tell it to do something it can't so you'll have to do either:

if c in a:
    a.remove(c)

or:

try:
    a.remove(c)
except ValueError:
    pass

An Exception isn't necessarily a bad thing as long as it's one you're expecting and handle properly.

Jag answered 8/5, 2010 at 8:2 Comment(8)
Prevention is better than cure. If you can check for exceptional conditions first (example a), you should.Dilemma
Whilst this is true in other languages, in Python it is "easier to ask for forgiveness than permission." docs.python.org/2/glossary.html#term-eafpJag
@Gusdor: if the list is shared between threads then a.remove(c) might fail anyway despite the if c in a check (a could be modified in another thread after the c in a check but before the a.remove(c) call). try/except or locks could be used to avoid the race condition.Lemming
@J.F.Sebastian if a list is shared between threads and you are not applying critical sections then you have bigger problems.Dilemma
@Gusdor, the Pythonique idiom is to try without checking and catch the exception if it occurs. It is more efficient (only one lookup instead of two), albeit a little uglierUrease
@Gusdor: what are the bigger problems exactly? Python allows to use a list from multiple threads e.g., CPython holds GIL while a.remove(c) is performed. See Are lists thread-safeLemming
Python's exception handling is very good, and faster than equivalentif based code when the exception isn't raised. However, when the exception is raised, it's considerably slower. If the exception is likely to be raised more than 5-10% of the time, then a "look before you leap" strategy is probably faster.Irrelevance
In proper languages the operation would only throw if it was modified by multiple threads, while removal was happening. Otherwise a boolean would be returned indicating if the underlying collection was modified.Applause
D
90

You can do

a=[1,2,3,4]
if 6 in a:
    a.remove(6)

but above need to search 6 in list a 2 times, so try except would be faster

try:
    a.remove(6)
except:
    pass
Dihedral answered 8/5, 2010 at 7:57 Comment(0)
I
73

Consider:

a = [1,2,2,3,4,5]

To take out all occurrences, you could use the filter function in python. For example, it would look like:

a = list(filter(lambda x: x!= 2, a))

So, it would keep all elements of a != 2.

To just take out one of the items use

a.remove(2)
Ineducation answered 11/8, 2014 at 19:55 Comment(3)
Why do you wrap filter() in another list()? According to the manual, it already returns a list.Plunk
@OlafDietsche In Python 3.x, it returns a filter object (in 2.x, it returns a list), so I have to cast "a" to a list for it to have any functionality.Ineducation
I would never use filter with a lambda and wrapped in list like that. Just use a list comprehension: a = [x for x in a if x != 2].Peaslee
L
24

Here's how to do it inplace (without list comprehension):

def remove_all(seq, value):
    pos = 0
    for item in seq:
        if item != value:
           seq[pos] = item
           pos += 1
    del seq[pos:]
Lemming answered 8/5, 2010 at 14:57 Comment(2)
Very clever - I really like this - unfortunately it seems to be as inefficient as the most popular answer. gil's solution is actually much faster for giant lists with only a few occurrences of the value you wish to remove.Blister
@Blister The fastest way would be a separate question. My money are on list comprehension in the general case. This solution should perform really well if the value is frequent in the input list and list comprehension is not used. Try Pypy, numpy data in Cython. [@Gill's answer is O(n*n) unnecessarily (compare 1e6 and 1e12 – you don't want to risk the latter). while 1: L.remove(value) and return on ValueError might work well with a few values or small lists in CPython.Lemming
O
17

As stated by numerous other answers, list.remove() will work, but throw a ValueError if the item wasn't in the list. With python 3.4+, there's an interesting approach to handling this, using the suppress contextmanager:

from contextlib import suppress
with suppress(ValueError):
    a.remove('b')
Otherworldly answered 19/9, 2017 at 11:36 Comment(0)
U
15

If you know what value to delete, here's a simple way (as simple as I can think of, anyway):

a = [0, 1, 1, 0, 1, 2, 1, 3, 1, 4]
while a.count(1) > 0:
    a.remove(1)

You'll get [0, 0, 2, 3, 4]

Uninhibited answered 28/3, 2013 at 21:20 Comment(4)
Why not use while 1 in a: as the loop structure?Gloomy
This is O(n^2) where a comprehension would be O(n).Aureomycin
Of course @MadPhysicist is right, and TerminalDilettante's version is a lot more pythonic, even if we don't care about performance. 2013 was I just began to learn Python and nowadays I'm quite often ashamed of what I wrote back then.Uninhibited
Nevertheless, this changes the list in place without copying it which may be desirable in specific cases.Colous
S
14

In one line:

a.remove('b') if 'b' in a else None

sometimes it useful.

Even easier:

if 'b' in a: a.remove('b')
Sora answered 23/11, 2018 at 13:2 Comment(0)
O
13

Another possibility is to use a set instead of a list, if a set is applicable in your application.

IE if your data is not ordered, and does not have duplicates, then

my_set=set([3,4,2])
my_set.discard(1)

is error-free.

Often a list is just a handy container for items that are actually unordered. There are questions asking how to remove all occurences of an element from a list. If you don't want dupes in the first place, once again a set is handy.

my_set.add(3)

doesn't change my_set from above.

Outrage answered 1/3, 2016 at 23:13 Comment(0)
T
11

If your elements are distinct, then a simple set difference will do.

c = [1,2,3,4,'x',8,6,7,'x',9,'x']
z = list(set(c) - set(['x']))
print z
[1, 2, 3, 4, 6, 7, 8, 9]
Tilt answered 11/8, 2016 at 14:12 Comment(1)
If your elements are distinct and you don’t care about order.Zoo
O
10

This example is fast and will delete all instances of a value from the list:

a = [1,2,3,1,2,3,4]
while True:
    try:
        a.remove(3)
    except:
        break
print a
>>> [1, 2, 1, 2, 4]
Ottilie answered 30/8, 2015 at 15:43 Comment(1)
if you do this you should really only break on except ValueError.Altercate
M
9

Finding a value in a list and then deleting that index (if it exists) is easier done by just using list's remove method:

>>> a = [1, 2, 3, 4]
>>> try:
...   a.remove(6)
... except ValueError:
...   pass
... 
>>> print a
[1, 2, 3, 4]
>>> try:
...   a.remove(3)
... except ValueError:
...   pass
... 
>>> print a
[1, 2, 4]

If you do this often, you can wrap it up in a function:

def remove_if_exists(L, value):
  try:
    L.remove(value)
  except ValueError:
    pass
Modify answered 8/5, 2010 at 7:58 Comment(0)
G
6

We can also use .pop:

>>> lst = [23,34,54,45]
>>> remove_element = 23
>>> if remove_element in lst:
...     lst.pop(lst.index(remove_element))
... 
23
>>> lst
[34, 54, 45]
>>> 
Gibbons answered 5/4, 2017 at 11:30 Comment(0)
C
5

Many of the answers here involve creating a new list. This involves copying all the data from the old list to the new list (except for the removed items). If your list is huge, you may not be able to afford it (or you should not want to).

In these cases, it is much faster to alter the list in place. If you have to remove more than 1 element from the list it can be tricky. Suppose you loop over the list, and remove an item, then the list changes and a standard for-loop will not take this into account. The result of the loop may not be what you expected.

Example:

a = [0, 1, 2, 3, 4, 5]
for i in a:
    a.remove(i)  # Remove all items
print(a)

Out: [1, 3, 5]

A simple solution is to loop through the list in reverse order. In this case you get:

a = [0, 1, 2, 3, 4, 5]
for i in reversed(a):
    a.remove(i)  # Remove all items
print(a)

Out: []

Then, if you need to only remove elements having some specific values, you can simply put an if statement in the loop resulting in:

a = [0, 1, 2, 3, 4, 5]
for i in reversed(a):
    if i == 2 or i == 3:  # Remove all items having value 2 or 3.
        a.remove(i)
print(a)

Out: [0, 1, 4, 5]
Colous answered 19/3, 2021 at 16:59 Comment(0)
S
4

Overwrite the list by indexing everything except the elements you wish to remove

>>> s = [5,4,3,2,1]
>>> s[0:2] + s[3:]
[5, 4, 2, 1]

More generally,

>>> s = [5,4,3,2,1]
>>> i = s.index(3)
>>> s[:i] + s[i+1:]
[5, 4, 2, 1]
Slabber answered 7/4, 2017 at 17:26 Comment(0)
L
4

With a for loop and a condition:

def cleaner(seq, value):    
    temp = []                      
    for number in seq:
        if number != value:
            temp.append(number)
    return temp

And if you want to remove some, but not all:

def cleaner(seq, value, occ):
    temp = []
    for number in seq:
        if number == value and occ:
            occ -= 1
            continue
        else:
            temp.append(number)
    return temp
Linden answered 5/5, 2017 at 21:12 Comment(0)
S
4
 list1=[1,2,3,3,4,5,6,1,3,4,5]
 n=int(input('enter  number'))
 while n in list1:
    list1.remove(n)
 print(list1)
Synergism answered 24/7, 2017 at 16:54 Comment(1)
It's without using filter functionSynergism
V
4

When nums is the list and c is the value to be removed:

To remove the first occurrence of c in the list, just do:

if c in nums:
    nums.remove(c)

To remove all occurrences of c from the list do:

while c in nums:
    nums.remove(c)

Adding the exception handling would be the best practice, but I mainly wanted to show how to remove all occurrences of an element from the list.

Vehement answered 29/9, 2021 at 5:15 Comment(0)
I
3

Say for example, we want to remove all 1's from x. This is how I would go about it:

x = [1, 2, 3, 1, 2, 3]

Now, this is a practical use of my method:

def Function(List, Unwanted):
    [List.remove(Unwanted) for Item in range(List.count(Unwanted))]
    return List
x = Function(x, 1)
print(x)

And this is my method in a single line:

[x.remove(1) for Item in range(x.count(1))]
print(x)

Both yield this as an output:

[2, 3, 2, 3, 2, 3]

Hope this helps. PS, pleas note that this was written in version 3.6.2, so you might need to adjust it for older versions.

Interceptor answered 19/9, 2017 at 11:31 Comment(1)
In general, list-comprehension should not be used just for the side-effects, in this case - removing elements from another list. It is better to just use a regular loop and avoid the unnecessary extra list creationThrostle
T
1
arr = [1, 1, 3, 4, 5, 2, 4, 3]

# to remove first occurence of that element, suppose 3 in this example
arr.remove(3)

# to remove all occurences of that element, again suppose 3
# use something called list comprehension
new_arr = [element for element in arr if element!=3]

# if you want to delete a position use "pop" function, suppose 
# position 4 
# the pop function also returns a value
removed_element = arr.pop(4)

# u can also use "del" to delete a position
del arr[4]
Tympany answered 2/4, 2018 at 20:56 Comment(0)
M
1

you can use this for finding and removing specified Item from list

def find_and_delete_element(lst,item):
    for ele in lst:
        if ele == item:
            lst.remove(item)
    return lst
Mesomorphic answered 27/12, 2023 at 3:28 Comment(0)
A
0

This removes all instances of "-v" from the array sys.argv, and does not complain if no instances were found:

while "-v" in sys.argv:
    sys.argv.remove('-v')

You can see the code in action, in a file called speechToText.py:

$ python speechToText.py -v
['speechToText.py']

$ python speechToText.py -x
['speechToText.py', '-x']

$ python speechToText.py -v -v
['speechToText.py']

$ python speechToText.py -v -v -x
['speechToText.py', '-x']
Alcove answered 13/9, 2018 at 15:43 Comment(0)
I
0

Maybe your solutions works with ints, but It Doesnt work for me with dictionarys.

In one hand, remove() has not worked for me. But maybe it works with basic Types. I guess the code bellow is also the way to remove items from objects list.

In the other hand, 'del' has not worked properly either. In my case, using python 3.6: when I try to delete an element from a list in a 'for' bucle with 'del' command, python changes the index in the process and bucle stops prematurely before time. It only works if You delete element by element in reversed order. In this way you dont change the pending elements array index when you are going through it

Then, Im used:

c = len(list)-1
for element in (reversed(list)):
    if condition(element):
        del list[c]
    c -= 1
print(list)

where 'list' is like [{'key1':value1'},{'key2':value2}, {'key3':value3}, ...]

Also You can do more pythonic using enumerate:

for i, element in enumerate(reversed(list)):
    if condition(element):
        del list[(i+1)*-1]
print(list)
Improvident answered 23/11, 2018 at 11:44 Comment(0)
S
0

this is my answer, just use while and for

def remove_all(data, value):
    i = j = 0
    while j < len(data):
        if data[j] == value:
            j += 1
            continue
        data[i] = data[j]
        i += 1
        j += 1
    for x in range(j - i):
        data.pop()
Saltern answered 15/9, 2019 at 12:42 Comment(0)
P
0

Benchmark of some of the simplest method:

import random
from copy import copy
sample = random.sample(range(100000), 10000)
remove = random.sample(range(100000), 1000)

%%timeit
sample1 = copy(sample)
remove1 = copy(remove)

for i in reversed(sample1):
    if i in remove1:
        sample1.remove(i)
# 271 ms ± 16 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
# remove all instances

%%timeit
sample1 = copy(sample)
remove1 = copy(remove)

filtered = list(filter(lambda x: x not in remove1, sample1))
# 280 ms ± 18.9 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
# remove all instances

%%timeit
sample1 = copy(sample)
remove1 = copy(remove) 

filtered = [ele for ele in sample1 if ele not in remove1]
# 293 ms ± 72.1 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
# remove all instances

%%timeit
sample1 = copy(sample)
remove1 = copy(remove) 

for val in remove1:
    if val in sample1:
        sample1.remove(val)
# 558 ms ± 40.7 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
# only remove first occurrence

%%timeit
sample1 = copy(sample)
remove1 = copy(remove) 

for val in remove1:
    try:
        sample1.remove(val)
    except:
        pass
# 609 ms ± 11.7 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
# only remove first occurrence
Paganize answered 21/5, 2021 at 6:43 Comment(0)
T
0

This is a less efficient solution, but it still works:

a = [ ] // that is your list

b // element(s) you need to delete

counter = a.count(b)

while counter > 0:
    if b in a:
       a.remove(b)
       counter -= 1

print(a)
Teepee answered 1/5, 2022 at 17:44 Comment(0)
L
0

This is a variation of the other answers that use:

  • reversed()
  • list comprehension
  • list.remove(element)

As others have pointed out, reversed() is needed to ensure that the elements are deleted in reverse order, else, without it, when traversing forward, it will not process the record immediately to the right of the delete.

The difference is we use list comprehension to both iterate and delete the elements at the same time, so, no double traversal. We also use list comprehension to build the list of deleted elements.

a = [1,2,2,2,2,3,4,5]
deleted = [a.remove(n) or n for n in reversed(a) if n == 2]
print(deleted)
# [2, 2, 2, 2]
print(a)
# [1, 3, 4, 5]

For the values in the resultant list, we are using a.remove(n) or n. The left-hand expression, i.e. a.remove(n) always evaluates to None. So the or will always favor the right-hand expression, i.e. n. So, the resultant list will always be the list of deleted items. This is useful when the list contains more complex objects such as dictionaries.

materials = [{"n":"silver","t":"metal" },
             {"n":"iron"  ,"t":"metal" },
             {"n":"water" ,"t":"liquid"}]
deleted = [materials.remove(m) or m for m in reversed(materials) if m["t"] == "metal"]
print(deleted)
# [{'n': 'iron', 't': 'metal'}, {'n': 'silver', 't': 'metal'}]
print(materials)
# [{'n': 'water', 't': 'liquid'}]

The downside of this approach is it forces a temporary list to be built which, in most cases, you will discard shortly afterward. For example, in this example, the temporary list is discarded immediately after it was built:

a = [1,2,2,2,2,3,4,5]
[a.remove(n) or n for n in reversed(a) if n == 2]
print(a)
# [1, 3, 4, 5]

The saving grace of this solution is it implements the in-place deletion with 1 succinct line of python.

Libna answered 24/5, 2023 at 5:38 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.