RandomCoder
RandomCoder

Reputation: 2199

How to remove multiple items from a list in just one statement?

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?

Upvotes: 188

Views: 367019

Answers (10)

aluriak
aluriak

Reputation: 5847

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.

Upvotes: 281

Ayman_Negm
Ayman_Negm

Reputation: 21

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])

Upvotes: 0

Rajesh Khangar
Rajesh Khangar

Reputation: 11

we can remove multiple elements

list1=[1,2,3,4,5,200,30]

del list1[1:3]

print(list1)

[1,4,5,200,30]

Upvotes: 1

A. chahid
A. chahid

Reputation: 303

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]

Upvotes: 0

aless80
aless80

Reputation: 3332

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.

Upvotes: 0

Aakash Goel
Aakash Goel

Reputation: 1030

You can do it in one line by converting your lists to sets 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 sets don't preserve order). It also requires all elements in both of your lists to be hashable.

Upvotes: 53

Krishna Singhal
Krishna Singhal

Reputation: 661

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

Upvotes: 1

Vlad Bezden
Vlad Bezden

Reputation: 89537

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 0s\n{data=}\n{clean=}\n")


clean = [*filterfalse(lambda i: i in (0, 1), data)]
print(f"Remove 0s and 1s\n{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]

Upvotes: 3

Anwarvic
Anwarvic

Reputation: 12992

I don't know why everyone forgot to mention the amazing capability of sets 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']

Upvotes: 0

Darkonaut
Darkonaut

Reputation: 21654

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.

Upvotes: 2

Related Questions