525

In Python remove() will remove the first occurrence of value in a list.

How to remove all occurrences of a value from a list?

This is what I have in mind:

>>> remove_values_from_list([1, 2, 3, 4, 2, 2, 3], 2)
[1, 3, 4, 3]
Aran-Fey
  • 39,665
  • 11
  • 104
  • 149
riza
  • 16,274
  • 7
  • 29
  • 29

26 Answers26

687

Functional approach:

Python 3.x

>>> x = [1,2,3,2,2,2,3,4]
>>> list(filter((2).__ne__, x))
[1, 3, 3, 4]

or

>>> x = [1,2,3,2,2,2,3,4]
>>> list(filter(lambda a: a != 2, x))
[1, 3, 3, 4]

or

>>> [i for i in x if i != 2]

Python 2.x

>>> x = [1,2,3,2,2,2,3,4]
>>> filter(lambda a: a != 2, x)
[1, 3, 3, 4]
Mahmudul Hasan
  • 2,949
  • 1
  • 9
  • 9
Mark Rushakoff
  • 249,864
  • 45
  • 407
  • 398
  • 159
    Use the list comprehension over the filter+lambda; the former is more readable in addition to generally more efficient. – habnabit Jul 21 '09 at 04:28
  • 21
    s/generally/generally being/ – habnabit Jul 21 '09 at 04:29
  • 133
    The code for habnabit's suggestion looks like this: `[y for y in x if y != 2]` – coredumperror Apr 22 '13 at 22:12
  • 14
    I wouldn't call this solution the best. List comprehensions are faster and easier to understand while skimming through code. This would rather be more of a Perl way than Python. – Peter Nimroot Aug 13 '16 at 15:25
  • 11
    -1 for directly invoking `__ne__`. Comparing two values is a far more complex process than just calling `__eq__` or `__ne__` on one of them. It may work correctly here because you're only comparing numbers, but in the general case that's incorrect and a bug. – Aran-Fey Jun 04 '18 at 07:11
  • 3
    @habnabit This is probably going to get downvoted by the python crew, but the statement that the list comprehension is more readable is probably in the general case false. The filter higher order function concept exists in many more programming languages than list comprehensions as a concept (much less the specific list comprehension syntax as it exists in Python). Though I agree that the list comprehension is the "right" way to do this task in Python, if any one is confused why this answer has twice as many upvotes as the "right" answer, that is why. – ltc Jul 02 '19 at 23:34
  • 2
    Do **not** use dunder methods directly like that. A simple example: `(2).__ne__(2.)` returns `NotImplemented`, which is *truthy* – juanpa.arrivillaga Jul 26 '21 at 09:22
  • `list(filter(lambda))` should always be rewritten as a comprehension because it's almost always easier to read and always shorter--by 9 characters in this case. – wjandrea Dec 16 '21 at 06:00
282

You can use a list comprehension:

def remove_values_from_list(the_list, val):
   return [value for value in the_list if value != val]

x = [1, 2, 3, 4, 2, 2, 3]
x = remove_values_from_list(x, 2)
print x
# [1, 3, 4, 3]
mhawke
  • 84,695
  • 9
  • 117
  • 138
  • But, this way, it will check for each item in the list. – riza Jul 21 '09 at 03:19
  • 9
    How would you remove items without checking them? – Alexander Ljungberg Jul 21 '09 at 03:20
  • 24
    This doesn't modify the original list but returns a new list. – John Y Jul 21 '09 at 03:20
  • @Alexander Ljungberg: Is there a way to reduce the number of checking? – riza Jul 21 '09 at 03:21
  • 9
    @Selinap: No, this is optimal as it scans the list only once. In your original code both the `in` operator and `remove` method scan the entire list (up until they find a match) so you end up scanning the list multiple times that way. – John Kugelman Jul 21 '09 at 03:24
  • @Selinap: if you structure your data ahead of time in something like a binary tree you can hunt down all instances of a certain value without having to check all values in the data. What are you trying to accomplish? – Alexander Ljungberg Jul 21 '09 at 03:26
  • @John Y: "This doesn't modify the original list but returns a new list"... and then rebinds it - probably much faster than removing in place. – mhawke Jul 21 '09 at 03:27
  • 6
    @mhawke, @John Y: just use x[:] = ... instead of x = and it will be "in-place" rather than just rebinding the name 'x' (speed is essentially the same and MUCH faster than x.remove can be!!!). – Alex Martelli Jul 21 '09 at 03:33
  • 1
    Removing in-place can be very fast if you don't care about the order: move the last item over the one you're deleting, then when you're done scanning, truncate the items off the end. If you're not removing many elements, this may be faster in a lower level language--it moves less memory around. I suspect it's a wash in Python. – Glenn Maynard Jul 21 '09 at 03:36
  • Doing x[:] = y is probably going to make a second memory copy of the list, though, which will be slower (not by much, at least for typical small lists). – Glenn Maynard Jul 21 '09 at 03:39
  • 18
    I vote this up because after 6 years of Python I still don't understand Lambdas :) – neydroydrec Sep 29 '12 at 10:47
  • 3
    @Benjamin Lambdas are also known as 'anonymous functions'. Basically, they are functions you create on-the-fly, usually for a specific purpose, and just kind of injected into a certain spot in your code. As a side note, I am not entirely sure about Python, but in other languages (like `Scheme`), every function that you write is actually INTERNALLY converted and stored as a Lambda expression. Giving it some name to reference it by, and referring to it by that name, is syntactic sugar of sorts for the underlying Lambda expression. – Houdini May 24 '13 at 14:23
142

You can use slice assignment if the original list must be modified, while still using an efficient list comprehension (or generator expression).

>>> x = [1, 2, 3, 4, 2, 2, 3]
>>> x[:] = (value for value in x if value != 2)
>>> x
[1, 3, 4, 3]
A. Coady
  • 54,452
  • 8
  • 34
  • 40
  • filter and list comprehensions don't modify a list. slice assignment does. and the original example does. – A. Coady Jul 22 '09 at 23:24
  • 18
    I like this because it modifies the list that x refers to. If there are any other references to that list, they will be affected too. This is in contrast to the `x = [ v for v in x if x != 2 ]` proposals, that create a new list and change x to refer to it, leaving the original list untouched. – Hannes Sep 07 '16 at 05:06
53

Repeating the solution of the first post in a more abstract way:

>>> x = [1, 2, 3, 4, 2, 2, 3]
>>> while 2 in x: x.remove(2)
>>> x
[1, 3, 4, 3]
funk
  • 2,221
  • 1
  • 24
  • 23
  • 40
    It's O(n*n), though. – Hannes Sep 07 '16 at 04:45
  • @Hannes would not it be O(n) since it is going through the loop just once & at the same time removing the item ? – penta Mar 28 '19 at 04:01
  • 5
    Consider `x = [1] * 10000 + [2] * 1000`. The loop body executes 1000 times and .remove() has to skip 10000 elements every time it's invoked. That smells like O(n*n) to me but is no proof. I think the proof would be to assume that the number of 2s in the list is proportional to its length. That proportionality factor then disappears in big-O notation. The best case, though, of only a constant number of 2s in the list, is not O(n^2), just O(2n) which is O(n). – Hannes Apr 02 '19 at 06:13
41

See the simple solution

>>> [i for i in x if i != 2]

This will return a list having all elements of x without 2

Georgy
  • 12,464
  • 7
  • 65
  • 73
Shameem
  • 2,664
  • 17
  • 21
24

better solution with list comprehension

x = [i for i in x if i!=2]
Amr
  • 2,045
  • 14
  • 17
15

All of the answers above (apart from Martin Andersson's) create a new list without the desired items, rather than removing the items from the original list.

>>> import random, timeit
>>> a = list(range(5)) * 1000
>>> random.shuffle(a)

>>> b = a
>>> print(b is a)
True

>>> b = [x for x in b if x != 0]
>>> print(b is a)
False
>>> b.count(0)
0
>>> a.count(0)
1000

>>> b = a
>>> b = filter(lambda a: a != 2, x)
>>> print(b is a)
False

This can be important if you have other references to the list hanging around.

To modify the list in place, use a method like this

>>> def removeall_inplace(x, l):
...     for _ in xrange(l.count(x)):
...         l.remove(x)
...
>>> removeall_inplace(0, b)
>>> b is a
True
>>> a.count(0)
0

As far as speed is concerned, results on my laptop are (all on a 5000 entry list with 1000 entries removed)

  • List comprehension - ~400us
  • Filter - ~900us
  • .remove() loop - 50ms

So the .remove loop is about 100x slower........ Hmmm, maybe a different approach is needed. The fastest I've found is using the list comprehension, but then replace the contents of the original list.

>>> def removeall_replace(x, l):
....    t = [y for y in l if y != x]
....    del l[:]
....    l.extend(t)
  • removeall_replace() - 450us
Paul S
  • 7,645
  • 2
  • 24
  • 36
  • Why not just reassign the new list under the old address then? `def remove_all(x, l): return [y for y in l if y != x]` then `l = remove_all(3,l)` – Dannid Mar 01 '16 at 17:58
  • @Dannid That's the second method in the first code box. It creates a new list, and you're not modifying the old list. Any other references to the list will remain unfiltered. – Paul S Mar 10 '16 at 17:25
  • Ah, right. I got so caught up in defining a method, I overlooked the simple assignment you'd already done. – Dannid Mar 14 '16 at 21:19
6

Numpy approach and timings against a list/array with 1.000.000 elements:

Timings:

In [10]: a.shape
Out[10]: (1000000,)

In [13]: len(lst)
Out[13]: 1000000

In [18]: %timeit a[a != 2]
100 loops, best of 3: 2.94 ms per loop

In [19]: %timeit [x for x in lst if x != 2]
10 loops, best of 3: 79.7 ms per loop

Conclusion: numpy is 27 times faster (on my notebook) compared to list comprehension approach

PS if you want to convert your regular Python list lst to numpy array:

arr = np.array(lst)

Setup:

import numpy as np
a = np.random.randint(0, 1000, 10**6)

In [10]: a.shape
Out[10]: (1000000,)

In [12]: lst = a.tolist()

In [13]: len(lst)
Out[13]: 1000000

Check:

In [14]: a[a != 2].shape
Out[14]: (998949,)

In [15]: len([x for x in lst if x != 2])
Out[15]: 998949
MaxU - stand with Ukraine
  • 205,989
  • 36
  • 386
  • 419
5

At the cost of readability, I think this version is slightly faster as it doesn't force the while to reexamine the list, thus doing exactly the same work remove has to do anyway:

x = [1, 2, 3, 4, 2, 2, 3]
def remove_values_from_list(the_list, val):
    for i in range(the_list.count(val)):
        the_list.remove(val)

remove_values_from_list(x, 2)

print(x)
Martin Andersson
  • 18,072
  • 9
  • 87
  • 115
  • For the list you show in your code, this approach is about 36% slower than the list comprehension method (which returns a copy), according to my measurement. – djsmith Oct 14 '12 at 03:55
  • Good you noticed that. However, because I think it might have slipped your judgement, I was comparing my version with the very first proposal made by the question author. – Martin Andersson Oct 15 '12 at 08:01
5

To remove all duplicate occurrences and leave one in the list:

test = [1, 1, 2, 3]

newlist = list(set(test))

print newlist

[1, 2, 3]

Here is the function I've used for Project Euler:

def removeOccurrences(e):
  return list(set(e))
Jared Burrows
  • 54,294
  • 25
  • 151
  • 185
  • 2
    I needed to do this on a vector with 250k values, and it works like a charm. – rschwieb Mar 01 '13 at 00:13
  • are you doing something like project euler? – Jared Burrows Mar 01 '13 at 05:30
  • 1
    The answer is: yes! And I completely understand if having a vector that long sounds completely crazy to a competent programmer. I approach the problems there as a mathematician, not worrying about optimizing the solutions, and that can lead to solutions longer than the par. (Although I don't have any patience for solutions longer than 5 minutes.) – rschwieb Mar 01 '13 at 14:08
  • 7
    This will remove any ordering from the list. – asmeurer Jul 16 '13 at 22:03
  • This code snippet is only to remove occurrences. You will most likely have to resort after. – Jared Burrows Jul 17 '13 at 00:32
  • 4
    @JaredBurrows perhaps because it doesn't answer the question as it currently stands, but a quite different question. – drevicko Jun 15 '14 at 11:47
  • 8
    -1, this is not an answer to the OP's question. It is a solution to remove duplicates, which is a completely different matter. – Anoyz Jul 22 '16 at 11:18
5
a = [1, 2, 2, 3, 1]
to_remove = 1
a = [i for i in a if i != to_remove]
print(a)

Perhaps not the most pythonic but still the easiest for me haha

Ankit Sharma
  • 1,626
  • 1
  • 14
  • 21
3
for i in range(a.count(' ')):
    a.remove(' ')

Much simpler I believe.

Alex Gyoshev
  • 11,929
  • 4
  • 44
  • 74
marco
  • 57
  • 1
  • 3
    please edit your answer so as to improve clarity. Please make it clear what exactly your recommended code does, why it works and why this is your recommendation. Please also correctly format your question so that code is clearly discernible from the rest of your answer. – Ortund Nov 03 '16 at 14:39
2

I believe this is probably faster than any other way if you don't care about the lists order, if you do take care about the final order store the indexes from the original and resort by that.

category_ids.sort()
ones_last_index = category_ids.count('1')
del category_ids[0:ones_last_index]
  • 2
    I understand where your'e going, but this code won't work since you need also the start index and not just 0. – Shedokan Apr 27 '13 at 10:31
2

Let

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

The simplest and efficient solution as already posted before is

>>> x[:] = [v for v in x if v != 2]
>>> x
[1, 3, 4, 3]

Another possibility which should use less memory but be slower is

>>> for i in range(len(x) - 1, -1, -1):
        if x[i] == 2:
            x.pop(i)  # takes time ~ len(x) - i
>>> x
[1, 3, 4, 3]

Timing results for lists of length 1000 and 100000 with 10% matching entries: 0.16 vs 0.25 ms, and 23 vs 123 ms.

Timing with length 1000

Timing with length 100000

jolvi
  • 4,463
  • 2
  • 15
  • 13
1

Remove all occurrences of a value from a Python list

lists = [6.9,7,8.9,3,5,4.9,1,2.9,7,9,12.9,10.9,11,7]
def remove_values_from_list():
    for list in lists:
      if(list!=7):
         print(list)
remove_values_from_list()

Result: 6.9 8.9 3 5 4.9 1 2.9 9 12.9 10.9 11

Alternatively,

lists = [6.9,7,8.9,3,5,4.9,1,2.9,7,9,12.9,10.9,11,7]
def remove_values_from_list(remove):
    for list in lists:
      if(list!=remove):
        print(list)
remove_values_from_list(7)

Result: 6.9 8.9 3 5 4.9 1 2.9 9 12.9 10.9 11

Ivan
  • 34,531
  • 8
  • 55
  • 100
rafiqul786
  • 19
  • 2
1

I just did this for a list. I am just a beginner. A slightly more advanced programmer can surely write a function like this.

for i in range(len(spam)):
    spam.remove('cat')
    if 'cat' not in spam:
         print('All instances of ' + 'cat ' + 'have been removed')
         break
akshayk07
  • 2,092
  • 1
  • 20
  • 32
Asir Ajmal
  • 11
  • 2
1

No one has posted an optimal answer for time and space complexity, so I thought I would give it a shot. Here is a solution that removes all occurrences of a specific value without creating a new array and at an efficient time complexity. The drawback is that the elements do not maintain order.

Time complexity: O(n)
Additional space complexity: O(1)

def main():
    test_case([1, 2, 3, 4, 2, 2, 3], 2)     # [1, 3, 3, 4]
    test_case([3, 3, 3], 3)                 # []
    test_case([1, 1, 1], 3)                 # [1, 1, 1]


def test_case(test_val, remove_val):
    remove_element_in_place(test_val, remove_val)
    print(test_val)


def remove_element_in_place(my_list, remove_value):
    length_my_list = len(my_list)
    swap_idx = length_my_list - 1

    for idx in range(length_my_list - 1, -1, -1):
        if my_list[idx] == remove_value:
            my_list[idx], my_list[swap_idx] = my_list[swap_idx], my_list[idx]
            swap_idx -= 1

    for pop_idx in range(length_my_list - swap_idx - 1):
        my_list.pop() # O(1) operation


if __name__ == '__main__':
    main()
Josh
  • 2,232
  • 3
  • 15
  • 33
1

A lot of answers are really good. Here is a simple approach if you are a beginner in python in case you want to use the remove() method for sure.

rawlist = [8, 1, 8, 5, 8, 2, 8, 9, 8, 4]

ele_remove = 8

for el in rawlist:
    if el == ele_remove:
        rawlist.remove(ele_remove)

It may be slower for too large lists.

ARHAM RUMI
  • 441
  • 5
  • 11
  • You never want to modify an collection that you are iterating over. This will lead to all sorts of errors, depending on the programming language. – Suprateem Banerjee Jul 20 '22 at 02:58
  • @SuprateemBanerjee yeah in that case we can create a new list containing unique elements. Thanks by the way for another aspect – ARHAM RUMI Jul 20 '22 at 04:33
1

If your list contains only duplicates of only one element for example list_a=[0,0,0,0,0,0,1,3,4,6,7] the code below would be helpful:

list_a=[0,0,0,0,0,0,1,3,4,6,7]
def remove_element(element,the_list):
    the_list=list(set(the_list))
    the_list.remove(element)
    return the_list

list_a=remove_element(element=0,the_list=list_a)
print(list_a)

or

a=list(set(i for i in list_a if i!=2))
a.remove(2)

The basic idea is that the sets do not allow duplicates, so first I have converted the list into set(which removes the duplicates), then used .remove() function to remove the first instance of the element(as now we have only one instance per item).


But if you have duplicates of multiple elements, the below methods would help:

  1. List comprehension
list_a=[1, 2, 3, 4, 2, 2, 3]
remove_element=lambda element,the_list:[i for i in the_list if i!=element]
print(remove_element(element=2,the_list=list_a))
  1. Filter
list_a=[1, 2, 3, 4, 2, 2, 3]
a=list(filter(lambda a: a != 2, list_a))
print(a)
  1. While loop
list_a=[1, 2, 3, 4, 2, 2, 3]
def remove_element(element,the_list):
    while element in the_list:the_list.remove(element)
    return the_list
print(remove_element(2,list_a))
  1. for loop (same as List comprehension)
list_a=[1, 2, 3, 4, 2, 2, 3]
a=[]
for i in list_a:
    if i!=2:
        a.append(i)
print(a)
Faraaz Kurawle
  • 1,085
  • 6
  • 24
0

If you didn't have built-in filter or didn't want to use extra space and you need a linear solution...

def remove_all(A, v):
    k = 0
    n = len(A)
    for i in range(n):
        if A[i] !=  v:
            A[k] = A[i]
            k += 1

    A = A[:k]
Moobius
  • 57
  • 1
  • 4
0
hello =  ['h', 'e', 'l', 'l', 'o', ' ', 'w', 'o', 'r', 'l', 'd']
#chech every item for a match
for item in range(len(hello)-1):
     if hello[item] == ' ': 
#if there is a match, rebuild the list with the list before the item + the list after the item
         hello = hello[:item] + hello [item + 1:]
print hello

['h', 'e', 'l', 'l', 'o', 'w', 'o', 'r', 'l', 'd']

SaNaMeDiO
  • 1
  • 2
0

We can also do in-place remove all using either del or pop:

import random

def remove_values_from_list(lst, target):
    if type(lst) != list:
        return lst

    i = 0
    while i < len(lst):
        if lst[i] == target:
            lst.pop(i)  # length decreased by 1 already
        else:
            i += 1

    return lst

remove_values_from_list(None, 2)
remove_values_from_list([], 2)
remove_values_from_list([1, 2, 3, 4, 2, 2, 3], 2)
lst = remove_values_from_list([random.randrange(0, 10) for x in range(1000000)], 2)
print(len(lst))


Now for the efficiency:

In [21]: %timeit -n1 -r1 x = random.randrange(0,10)
1 loop, best of 1: 43.5 us per loop

In [22]: %timeit -n1 -r1 lst = [random.randrange(0, 10) for x in range(1000000)]
g1 loop, best of 1: 660 ms per loop

In [23]: %timeit -n1 -r1 lst = remove_values_from_list([random.randrange(0, 10) for x in range(1000000)]
    ...: , random.randrange(0,10))
1 loop, best of 1: 11.5 s per loop

In [27]: %timeit -n1 -r1 x = random.randrange(0,10); lst = [a for a in [random.randrange(0, 10) for x in
    ...:  range(1000000)] if x != a]
1 loop, best of 1: 710 ms per loop

As we see that in-place version remove_values_from_list() does not require any extra memory, but it does take so much more time to run:

  • 11 seconds for inplace remove values
  • 710 milli seconds for list comprehensions, which allocates a new list in memory
tuxdna
  • 8,257
  • 4
  • 43
  • 61
0

You can convert your list to numpy.array and then use np.delete and pass the indices of the element and its all occurrences.

import numpy as np

my_list = [1, 2, 3, 4, 5, 6, 7, 3, 4, 5, 6, 7]
element_to_remove = 3
my_array = np.array(my_list)

indices = np.where(my_array == element_to_remove)
my_array = np.delete(my_array, indices)   
my_list = my_array.tolist()

print(my_list)

#output
[1, 2, 4, 5, 6, 7, 4, 5, 6, 7]
Hamzah
  • 8,175
  • 3
  • 19
  • 43
-1

About the speed!

import time
s_time = time.time()

print 'start'
a = range(100000000)
del a[:]
print 'finished in %0.2f' % (time.time() - s_time)
# start
# finished in 3.25

s_time = time.time()
print 'start'
a = range(100000000)
a = []
print 'finished in %0.2f' % (time.time() - s_time)
# start
# finished in 2.11
-3
p=[2,3,4,4,4]
p.clear()
print(p)
[]

Only with Python 3

Zulu
  • 8,765
  • 9
  • 49
  • 56
  • 3
    Hilariously, this is within the scope of the question asked and is correct. – Erich Aug 28 '17 at 22:26
  • I don't see how it is correct. This will remove *all items* from the list, not *all occurrences of a value*. – Georgy Feb 19 '20 at 15:10
-6

What's wrong with:

Motor=['1','2','2']
for i in Motor:
   if i != '2':
       print(i)
print(motor)
Daniel Walker
  • 6,380
  • 5
  • 22
  • 45