仅需一条语句即可从Python列表中删除多个项目


107

在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只需要一个参数。

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

PS我已经使用delremove。有人可以解释这两者之间的区别还是相同?

谢谢


1
回答第二个问题:del按索引删除项目。remove列表的功能查找项目的索引,然后调用del该索引。
亚伦·克里斯蒂安森

Answers:


159

在Python中,创建新对象通常比修改现有对象要好:

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)是一小组元素),则使用a set可以提高性能,因为in操作在O(1)中:

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

请注意,正如注释中所建议和此处建议的那样,以下内容可以节省更多时间,避免在每个循环中构建该集合:

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

一个布隆过滤器也是一个不错的解决方案,如果内存是不便宜。


我喜欢第一个答案。我没有列出新的清单,很好。谢谢!
RandomCoder

该集合是在python 2中优化的还是仅在python 3中优化的?我的意思是说,生成字节码时,集合仅创建一次吗?
喀拉

根据定义,Set已针对in操作进行了优化。请参阅此基准,以比较四个原始数据结构。是的,集合在每个循环建立,如建议在这里,因此保存设置在一个专用的变量在发电机表达式中使用可以节省时间。
aluriak

@RandomCoder实际上,您创建了一个新列表,只是重用了一个名称。您可以通过比较id(item_list)之前和之后进行检查item_list = [e for e in item_list if e not in ('item', 5)]。检查我的答案以查看如何在适当位置修改列表。
Darkonaut

20
item_list = ['item', 5, 'foo', 3.14, True]
list_to_remove=['item', 5, 'foo']

删除后的最终清单应如下

final_list=[3.14, True]

单行代码

final_list= list(set(item_list).difference(set(list_to_remove)))

输出如下

final_list=[3.14, True]

13
不,它会随机播放列表中的项目。仅当项目的顺序无关紧要时才使用,它经常这样做。
清道夫

5
这还将从列表中删除重复项。但这对示例列表并不重要
tschale

1
这个答案是不正确的,并且可能导致严重的错误,为什么要投票?
omerfarukdogan

1
它将删除重复项!答案可能会导致严重的错误,请不要使用。
user2698178 '19

2

我不知道为什么每个人都忘记提及setpython 中s 的惊人功能。您可以简单地将列表转换为集合,然后使用以下简单表达式删除要删除的任何内容:

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

6
但是不保持对象的顺序。
阿斯特丽德

并且还将删除列表中可能存在的重复项。
kyriakosSt

1

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


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扩展名:

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

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


1

您可以从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]

0

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

我不完全理解为什么您不喜欢.remove而是使用.index(value)获得与值相对应的第一个索引:

ind=item_list.index('item')

然后删除相应的值:

del item_list.pop[ind]

.index(value)获取值的第一次出现,.remove(value)删除值的第一次出现


如果不需要结果值,请考虑使用del item_list[ind]代替pop
kojiro

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.