How to remove multiple items from a list in just one statement?
Question:
In python, I know how to remove items from a list:
item_list = ['item', 5, 'foo', 3.14, True]
item_list.remove('item')
item_list.remove(5)
The above code removes the values 5 and ‘item’ from item_list
.
But when there is a lot of stuff to remove, I have to write many lines of:
item_list.remove("something_to_remove")
If I know the index of what I am removing, I use:
del item_list[x]
where x is the index of the item I want to remove.
If I know the index of all of the numbers that I want to remove, I’ll use some sort of loop to del
the items at the indices.
But what if I don’t know the indices of the items I want to remove?
I tried item_list.remove('item', 'foo')
, but I got an error saying that remove
only takes one argument.
Is there a way to remove multiple items from a list in a single statement?
P.S. I’ve used del
and remove
. Can someone explain the difference between these two, or are they the same?
Answers:
In Python, creating a new object e.g. with a list comprehension is often better than modifying an existing one:
item_list = ['item', 5, 'foo', 3.14, True]
item_list = [e for e in item_list if e not in ('item', 5)]
… which is equivalent to:
item_list = ['item', 5, 'foo', 3.14, True]
new_list = []
for e in item_list:
if e not in ('item', 5):
new_list.append(e)
item_list = new_list
In case of a big list of filtered out values (here, ('item', 5)
is a small set of elements), using a set
is faster as the in
operation is O(1) time complexity on average. It’s also a good idea to build the iterable you’re removing first, so that you’re not creating it on every iteration of the list comprehension:
unwanted = {'item', 5}
item_list = [e for e in item_list if e not in unwanted]
A bloom filter is also a good solution if memory is not cheap.
But what if I don’t know the indices of the items I want to remove?
I do not exactly understand why you do not like .remove but to get the first index corresponding to a value use .index(value):
ind=item_list.index('item')
then remove the corresponding value:
del item_list[ind]
.index(value) gets the first occurrence of value, and .remove(value) removes the first occurrence of value. You are welcome.
You can do it in one line by converting your lists to set
s and using set.difference
:
item_list = ['item', 5, 'foo', 3.14, True]
list_to_remove = ['item', 5, 'foo']
final_list = list(set(item_list) - set(list_to_remove))
Would give you the following output:
final_list = [3.14, True]
Note: this will remove duplicates in your input list and the elements in the output can be in any order (because set
s don’t preserve order). It also requires all elements in both of your lists to be hashable.
I’m reposting my answer from here because I saw it also fits in here.
It allows removing multiple values or removing only duplicates of these values
and returns either a new list or modifies the given list in place.
def removed(items, original_list, only_duplicates=False, inplace=False):
"""By default removes given items from original_list and returns
a new list. Optionally only removes duplicates of `items` or modifies
given list in place.
"""
if not hasattr(items, '__iter__') or isinstance(items, str):
items = [items]
if only_duplicates:
result = []
for item in original_list:
if item not in items or item not in result:
result.append(item)
else:
result = [item for item in original_list if item not in items]
if inplace:
original_list[:] = result
else:
return result
Docstring extension:
"""
Examples:
---------
>>>li1 = [1, 2, 3, 4, 4, 5, 5]
>>>removed(4, li1)
[1, 2, 3, 5, 5]
>>>removed((4,5), li1)
[1, 2, 3]
>>>removed((4,5), li1, only_duplicates=True)
[1, 2, 3, 4, 5]
# remove all duplicates by passing original_list also to `items`.:
>>>removed(li1, li1, only_duplicates=True)
[1, 2, 3, 4, 5]
# inplace:
>>>removed((4,5), li1, only_duplicates=True, inplace=True)
>>>li1
[1, 2, 3, 4, 5]
>>>li2 =['abc', 'def', 'def', 'ghi', 'ghi']
>>>removed(('def', 'ghi'), li2, only_duplicates=True, inplace=True)
>>>li2
['abc', 'def', 'ghi']
"""
You should be clear about what you really want to do, modify an existing list, or make a new list with
the specific items missing. It’s important to make that distinction in case you have a second reference pointing
to the existing list. If you have, for example…
li1 = [1, 2, 3, 4, 4, 5, 5]
li2 = li1
# then rebind li1 to the new list without the value 4
li1 = removed(4, li1)
# you end up with two separate lists where li2 is still pointing to the
# original
li2
# [1, 2, 3, 4, 4, 5, 5]
li1
# [1, 2, 3, 5, 5]
This may or may not be the behaviour you want.
I don’t know why everyone forgot to mention the amazing capability of set
s in python. You can simply cast your list into a set and then remove whatever you want to remove in a simple expression like so:
>>> item_list = ['item', 5, 'foo', 3.14, True]
>>> item_list = set(item_list) - {'item', 5}
>>> item_list
{True, 3.14, 'foo'}
>>> # you can cast it again in a list-from like so
>>> item_list = list(item_list)
>>> item_list
[True, 3.14, 'foo']
You can use filterfalse function from itertools module
Example
import random
from itertools import filterfalse
random.seed(42)
data = [random.randrange(5) for _ in range(10)]
clean = [*filterfalse(lambda i: i == 0, data)]
print(f"Remove 0sn{data=}n{clean=}n")
clean = [*filterfalse(lambda i: i in (0, 1), data)]
print(f"Remove 0s and 1sn{data=}n{clean=}")
Output:
Remove 0s
data=[0, 0, 2, 1, 1, 1, 0, 4, 0, 4]
clean=[2, 1, 1, 1, 4, 4]
Remove 0s and 1s
data=[0, 0, 2, 1, 1, 1, 0, 4, 0, 4]
clean=[2, 4, 4]
You Can use this –
Suppose we have a list, l = [1,2,3,4,5]
We want to delete last two items in a single statement
del l[3:]
We have output:
l = [1,2,3]
Keep it Simple
Suppose we have my_list as below. We would like to remove the duplicated 0’s from our list. By using remove(), only one 0 can be removed, whereas the next code can remove all the duplicated 0’s at once:
my_list = [1, 2, 3, 0, 0, 0, 3, 4]
list(filter(lambda a: a != 0, my_list))
output:
[1, 3, 3, 4]
we can remove multiple elements
list1=[1,2,3,4,5,200,30]
del list1[1:3]
print(list1)
[1,4,5,200,30]
You can combine the numpy array and set function to end up with a new array that only shows the elements you want to keep.
import numpy as np
# given an array A:
A = [5,78,423,87,45,78,4]
# first convert your array to a numpy array
A_np = np.array(A)
# specify the indices you want to remove
inds_to_be_deleted = [3,5]
# find the remaining indices using set function
remaining_inds = list(set(range(len(A)))-set(inds_to_be_deleted))
# the new array will only contain the elements at the remaining indices
A_new = A_np[remaining_inds]
which gives you this output:
array([ 5, 78, 423, 45, 4])
In python, I know how to remove items from a list:
item_list = ['item', 5, 'foo', 3.14, True]
item_list.remove('item')
item_list.remove(5)
The above code removes the values 5 and ‘item’ from item_list
.
But when there is a lot of stuff to remove, I have to write many lines of:
item_list.remove("something_to_remove")
If I know the index of what I am removing, I use:
del item_list[x]
where x is the index of the item I want to remove.
If I know the index of all of the numbers that I want to remove, I’ll use some sort of loop to del
the items at the indices.
But what if I don’t know the indices of the items I want to remove?
I tried item_list.remove('item', 'foo')
, but I got an error saying that remove
only takes one argument.
Is there a way to remove multiple items from a list in a single statement?
P.S. I’ve used del
and remove
. Can someone explain the difference between these two, or are they the same?
In Python, creating a new object e.g. with a list comprehension is often better than modifying an existing one:
item_list = ['item', 5, 'foo', 3.14, True]
item_list = [e for e in item_list if e not in ('item', 5)]
… which is equivalent to:
item_list = ['item', 5, 'foo', 3.14, True]
new_list = []
for e in item_list:
if e not in ('item', 5):
new_list.append(e)
item_list = new_list
In case of a big list of filtered out values (here, ('item', 5)
is a small set of elements), using a set
is faster as the in
operation is O(1) time complexity on average. It’s also a good idea to build the iterable you’re removing first, so that you’re not creating it on every iteration of the list comprehension:
unwanted = {'item', 5}
item_list = [e for e in item_list if e not in unwanted]
A bloom filter is also a good solution if memory is not cheap.
But what if I don’t know the indices of the items I want to remove?
I do not exactly understand why you do not like .remove but to get the first index corresponding to a value use .index(value):
ind=item_list.index('item')
then remove the corresponding value:
del item_list[ind]
.index(value) gets the first occurrence of value, and .remove(value) removes the first occurrence of value. You are welcome.
You can do it in one line by converting your lists to set
s and using set.difference
:
item_list = ['item', 5, 'foo', 3.14, True]
list_to_remove = ['item', 5, 'foo']
final_list = list(set(item_list) - set(list_to_remove))
Would give you the following output:
final_list = [3.14, True]
Note: this will remove duplicates in your input list and the elements in the output can be in any order (because set
s don’t preserve order). It also requires all elements in both of your lists to be hashable.
I’m reposting my answer from here because I saw it also fits in here.
It allows removing multiple values or removing only duplicates of these values
and returns either a new list or modifies the given list in place.
def removed(items, original_list, only_duplicates=False, inplace=False):
"""By default removes given items from original_list and returns
a new list. Optionally only removes duplicates of `items` or modifies
given list in place.
"""
if not hasattr(items, '__iter__') or isinstance(items, str):
items = [items]
if only_duplicates:
result = []
for item in original_list:
if item not in items or item not in result:
result.append(item)
else:
result = [item for item in original_list if item not in items]
if inplace:
original_list[:] = result
else:
return result
Docstring extension:
"""
Examples:
---------
>>>li1 = [1, 2, 3, 4, 4, 5, 5]
>>>removed(4, li1)
[1, 2, 3, 5, 5]
>>>removed((4,5), li1)
[1, 2, 3]
>>>removed((4,5), li1, only_duplicates=True)
[1, 2, 3, 4, 5]
# remove all duplicates by passing original_list also to `items`.:
>>>removed(li1, li1, only_duplicates=True)
[1, 2, 3, 4, 5]
# inplace:
>>>removed((4,5), li1, only_duplicates=True, inplace=True)
>>>li1
[1, 2, 3, 4, 5]
>>>li2 =['abc', 'def', 'def', 'ghi', 'ghi']
>>>removed(('def', 'ghi'), li2, only_duplicates=True, inplace=True)
>>>li2
['abc', 'def', 'ghi']
"""
You should be clear about what you really want to do, modify an existing list, or make a new list with
the specific items missing. It’s important to make that distinction in case you have a second reference pointing
to the existing list. If you have, for example…
li1 = [1, 2, 3, 4, 4, 5, 5]
li2 = li1
# then rebind li1 to the new list without the value 4
li1 = removed(4, li1)
# you end up with two separate lists where li2 is still pointing to the
# original
li2
# [1, 2, 3, 4, 4, 5, 5]
li1
# [1, 2, 3, 5, 5]
This may or may not be the behaviour you want.
I don’t know why everyone forgot to mention the amazing capability of set
s in python. You can simply cast your list into a set and then remove whatever you want to remove in a simple expression like so:
>>> item_list = ['item', 5, 'foo', 3.14, True]
>>> item_list = set(item_list) - {'item', 5}
>>> item_list
{True, 3.14, 'foo'}
>>> # you can cast it again in a list-from like so
>>> item_list = list(item_list)
>>> item_list
[True, 3.14, 'foo']
You can use filterfalse function from itertools module
Example
import random
from itertools import filterfalse
random.seed(42)
data = [random.randrange(5) for _ in range(10)]
clean = [*filterfalse(lambda i: i == 0, data)]
print(f"Remove 0sn{data=}n{clean=}n")
clean = [*filterfalse(lambda i: i in (0, 1), data)]
print(f"Remove 0s and 1sn{data=}n{clean=}")
Output:
Remove 0s
data=[0, 0, 2, 1, 1, 1, 0, 4, 0, 4]
clean=[2, 1, 1, 1, 4, 4]
Remove 0s and 1s
data=[0, 0, 2, 1, 1, 1, 0, 4, 0, 4]
clean=[2, 4, 4]
You Can use this –
Suppose we have a list, l = [1,2,3,4,5]
We want to delete last two items in a single statement
del l[3:]
We have output:
l = [1,2,3]
Keep it Simple
Suppose we have my_list as below. We would like to remove the duplicated 0’s from our list. By using remove(), only one 0 can be removed, whereas the next code can remove all the duplicated 0’s at once:
my_list = [1, 2, 3, 0, 0, 0, 3, 4]
list(filter(lambda a: a != 0, my_list))
output:
[1, 3, 3, 4]
we can remove multiple elements
list1=[1,2,3,4,5,200,30]
del list1[1:3]
print(list1)
[1,4,5,200,30]
You can combine the numpy array and set function to end up with a new array that only shows the elements you want to keep.
import numpy as np
# given an array A:
A = [5,78,423,87,45,78,4]
# first convert your array to a numpy array
A_np = np.array(A)
# specify the indices you want to remove
inds_to_be_deleted = [3,5]
# find the remaining indices using set function
remaining_inds = list(set(range(len(A)))-set(inds_to_be_deleted))
# the new array will only contain the elements at the remaining indices
A_new = A_np[remaining_inds]
which gives you this output:
array([ 5, 78, 423, 45, 4])