【问题标题】:Remove multiple items from a Python list in just one statement仅在一个语句中从 Python 列表中删除多个项目
【发布时间】:2016-03-28 18:38:13
【问题描述】:

在 python 中,我知道如何从列表中删除项目:

item_list = ['item', 5, 'foo', 3.14, True]
item_list.remove('item')
item_list.remove(5)

上面的代码从item_list 中删除了值5 和'item'。 但是当要删除的东西很多时,我必须写很多行:

item_list.remove("something_to_remove")

如果我知道要删除的索引,我会使用:

del item_list[x]

其中 x 是我要删除的项目的索引。

如果我知道要删除的所有数字的索引,我将使用某种循环来del 索引处的项目。

但是如果我不知道要删除的项目的索引怎么办?

我尝试了item_list.remove('item', 'foo'),但我收到一条错误消息,指出remove 只接受一个参数。

有没有办法在单个语句中从列表中删除多个项目?

附:我用过delremove。谁能解释一下这两者的区别,还是一样?

【问题讨论】:

  • 回答您的第二个问题:del 按索引删除项目。列表的remove 函数查找项目的索引,然后在该索引上调用del
  • 您的列表可以包含重复项吗? l.remove(value) 只删除第一次出现的值。考虑列表 ['a', 'b', 'a', 'c', 'b', 'a']。如果您想删除所有出现的值,使用列表推导比迭代执行 del.remove() 更轻松。

标签: python list list-comprehension


【解决方案1】:

在 Python 中,创建一个新对象,例如使用list comprehension 通常比修改现有的更好:

item_list = ['item', 5, 'foo', 3.14, True]
item_list = [e for e in item_list if e not in ('item', 5)]

...相当于:

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

如果过滤掉的值列表很大(这里,('item', 5) 是一小组元素),使用set 比使用in 操作is O(1) time complexity on average 更快。首先构建要删除的可迭代对象也是一个好主意,这样您就不会在列表理解的每次迭代中都创建它:

unwanted = {'item', 5}
item_list = [e for e in item_list if e not in unwanted]

如果内存不便宜,bloom filter 也是一个不错的解决方案。

【讨论】:

  • 这个集合是在 python 2 中优化的,还是只在 python 3 中优化的?我的意思是在生成字节码时只创建一次集合吗?
  • 设置为 by definition,针对 in 操作进行了优化。请参阅this benchmarks 了解四种原始数据结构的比较。是的,集合是在每个循环中构建的,正如here 建议的那样,因此将集合保存在专用变量中以在生成器表达式中使用可以节省时间。
  • 我遇到了这个问题。我只想指出,原始列表可能包含重复项,删除元素的意图可能只是删除与删除列表中一样多的元素。上述方法最终将消除所有重复项。不需要正确的行为。
  • @aluriak 从 python 3.9.7 开始的基准测试似乎给出了不同的结果。如果您有一个要过滤的复杂迭代,那么预先构建迭代是最好的,但是 set 与 list 给出的结果大致相同。对于简单的可迭代对象(小型可迭代对象的简单成员),set 的性能优于列表。见this adaptation of your experiment
  • 当您介绍一个重要的新概念(例如 OP 几乎可以肯定以前从未见过并且在大多数语言中不存在的列表理解)时,请为其命名(并超链接)。不要只向他们展示代码。
【解决方案2】:

您可以通过将列表转换为sets 并使用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))

会给你以下输出:

final_list = [3.14, True]

注意:这将删除输入列表中的重复项,并且输出中的元素可以是任意顺序(因为sets 不保留顺序)。它还要求两个列表中的所有元素都是hashable

【讨论】:

  • 不,它会随机播放列表中的项目。仅当项目的顺序无关紧要时才使用,它经常这样做。
  • 这也会从列表中删除重复项。但这对于示例列表并不重要
  • 它将删除重复项!答案可能会导致严重的bug,请不要使用。
【解决方案3】:

你可以使用itertools模块中的filterfalse函数

例子

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=}")

输出:

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]

【讨论】:

    【解决方案4】:

    我从here 转发我的答案,因为我看到它也适合这里。 它允许删除多个值或仅删除这些值的重复项 并返回一个新列表或修改给定的列表。


    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
    

    文档字符串扩展:

    """
    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']
    """
    

    您应该清楚自己真正想要做什么,修改现有列表,或创建一个新列表 缺少的具体项目。如果您有第二个参考点,那么区分这一点很重要 到现有列表。例如,如果您有...

    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]
    

    这可能是也可能不是您想要的行为。

    【讨论】:

      【解决方案5】:

      不知道为什么大家都忘了提到sets 在 python 中的惊人能力。您可以简单地将您的列表转换为一个集合,然后在一个简单的表达式中删除您想要删除的任何内容,如下所示:

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

      【讨论】:

      • 虽然不保持对象的顺序。
      • 并且还将删除列表中可能存在的重复项。
      • “为什么每个人都忘了提到 [...] sets”。因为他们没有stackoverflow.com/a/42243963/3064538
      【解决方案6】:

      但是如果我不知道要删除的项目的索引怎么办?

      我不完全明白你为什么不喜欢 .remove 而是使用 .index(value) 来获取与某个值对应的第一个索引:

      ind=item_list.index('item')
      

      然后去掉对应的值:

      del item_list[ind]
      

      .index(value) 获取第一次出现的 value,而 .remove(value) 删除第一次出现的 value。不客气。

      【讨论】:

      • 如果您不需要结果值,请考虑使用del item_list[ind] 而不是pop
      【解决方案7】:

      你可以用这个 -

      假设我们有一个列表,l = [1,2,3,4,5]

      我们要删除单个语句中的最后两项

      del l[3:]
      

      我们有输出:

      l = [1,2,3]

      保持简单

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2018-11-26
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2022-11-25
        相关资源
        最近更新 更多