Remove multiple items from a Python list in just one statement

前端 未结 7 1323
逝去的感伤
逝去的感伤 2020-12-02 06:28

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)
相关标签:
7条回答
  • 2020-12-02 06:47

    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']
    
    0 讨论(0)
  • 2020-12-02 06:47

    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]
    
    0 讨论(0)
  • 2020-12-02 06:52

    In Python, creating a new object 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.

    0 讨论(0)
  • 2020-12-02 06:52

    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.

    0 讨论(0)
  • 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.pop[ind]
    

    .index(value) gets the first occurrence of value, and .remove(value) removes the first occurrence of value

    0 讨论(0)
  • 2020-12-02 06:59

    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.

    0 讨论(0)
提交回复
热议问题