删除列表中的许多元素(python)

Delete many elements of list (python)

我有一个清单。

我可以通过执行以下操作删除元素i:

1
del L[i]

但是如果我有一组非连续索引要删除呢?

1
I=set([i1, i2, i3,...])

做:

1
2
for i in I:
     del L[i]

不起作用。

有什么想法吗?


Eine Minuten bitte, Ich hap eine
kleine Problemo avec diese Religione.
-- Eddie Izzard (doing his impression
of Martin Luther)

通过对列表进行反向迭代来删除以保留迭代器是解决此问题的常见方法。但另一个解决办法是把这变成一个不同的问题。不要使用某些条件(在您的情况下,索引存在于要删除的索引列表中)从列表中删除项目,而是创建一个新列表,将有问题的项目排除在外。

1
L[:] = [ item for i,item in enumerate(L) if i not in I ]

就这一点而言,您最初是从哪里得出I中的索引的?您可以组合获取要删除的索引和构建新列表的逻辑。假设这是一个对象列表,并且您只希望保留那些通过isValid测试的对象:

1
L[:] = [ item for item in L if item.isValid() ]

这比:

1
2
3
4
5
6
7
I = set()
for i in range(len(L)):
    if not L[i].isValid():
        I.add(i)

for i in sorted(I, reverse=True):
    del L[i]

在大多数情况下,我把关于"如何从列表中删除我不想要的项目"的任何问题转化为"如何创建只包含我想要的项目的新列表"。

编辑:根据Alex Martelli对这个问题的回答,将"L=…"改为"L[:]=…"。


1
2
for i in I:
    del L[i]

不起作用,因为(取决于顺序)您可能会使迭代器失效——这通常会显示为一些您打算删除的项,而这些项仍保留在列表中。

从列表中按索引的相反顺序删除项目总是安全的。最简单的方法是使用sorted():

1
2
for i in sorted(I, reverse=True):
    del L[i]


您可以使用numpy.delete如下:

1
2
3
4
5
import numpy as np
a = ['a', 'l', 3.14, 42, 'u']
I = [1, 3, 4]
np.delete(a, I).tolist()
# Returns: ['a', '3.14']

如果您不介意在末尾使用一个numpy数组,那么您可以省去.tolist()。您也应该看到一些非常重要的速度改进,使这个解决方案更具可扩展性。我没有对它进行基准测试,但是numpy操作是用C或Fortran编写的编译代码。


如果原始列表数据可以安全地转换为一个集合(即所有唯一值,不需要维护顺序),则还可以使用集合操作:

1
2
Lset = set(L)
newset = Lset.difference(I)

你也可以用一个包/多片装来做一些事情,尽管这可能不值得你这么做。PaulMcGuire的第二个listcomp解决方案当然最适合大多数情况。


1
L = [ item for item in L if L.index(item) not in I ]