一次从列表中删除多个索引 - Python

11

我的问题是我有一个列表
例如:

lst = [2, 5, 7, 12, 13]


lst.pop(3) #12
lst.pop(4) #13

由于lst[3]被移除,lst[4]也就不在了(超出范围)。这导致我出现了一个错误。现在,我知道你可能会说将代码更改为以下内容:

lst.pop(4) #13
lst.pop(3) #12

......它会修复错误,但我的问题是我的实际代码正在“弹出”随机数字,因此需要同时完成以避免错误。

是否有任何一种“同时弹出”的方法?…类似于这样的东西:

lst.pop(3, 4) #12 and 13 at once

谢谢任何答案。


不要将“list”用作变量名,这会掩盖内置类型。 - Martijn Pieters
5个回答

12
你可以使用列表推导式来重建列表:

你可以使用列表推导式来重建列表:

indices = {3, 4}
newlist = [v for i, v in enumerate(oldlist) if i not in indices]

我在这里使用了一个集合作为索引,因为与列表成员测试相比,集合成员测试更快。

请注意,删除操作(最好使用del lst[index])也会部分重建列表;在列表推导式中使用一个循环来执行此操作可能更有效率。

演示:

>>> oldlist = [2, 5, 7, 12, 13]
>>> indices = {3, 4}
>>> [v for i, v in enumerate(oldlist) if i not in indices]
[2, 5, 7]

我的上述示例是如何实现的? - Greg Peckory
@DennisCallanan:就像我发布的那样;我还给您进行了快速演示。 - Martijn Pieters
非常感谢!只是好奇,如果我有一个程序在每秒循环多次运行此操作。这种方法是否比仅从列表中“弹出”两个数字慢得多? - Greg Peckory
@DennisCallanan:除非你需要使用返回值,否则不要使用.pop();而是使用del lstobject[index]。这取决于列表对象的大小;如果您正在删除大型列表中的低索引,则列表推导式将更快。如果这是关键代码,请使用timeit模块进行自己的计时。 - Martijn Pieters
1
我的意思是oldlist = indices = {3, 4}这一行,你在接下来的两行中重新定义了这两个变量... - Bas Swinckels
显示剩余2条评论

4

您可以使用列表推导式来删除它们,这将创建一个新列表:

>>> lst = [2, 5, 7, 12, 13]
>>> [v for i, v in enumerate(lst) if i not in {4,3}]
[2, 5, 7]

你只需要将这个新列表再次赋值给 lst

0
如果你真的想通过原地删除来实现这个目标,那么显而易见的答案就是对要删除的索引进行排序:
>>> lst = [2, 5, 7, 12, 13]
>>> indices = {3, 4}
>>> for index in sorted(indices, reverse=True):
...     del lst[index]
>>> print(lst)
[2, 5, 7]

然而,请注意这是Martijn列表推导式的两倍代码量。如果您试图以此方式进行优化,(a)它几乎肯定是过早的优化,(b)很可能是一种恶化。

如果您这样做是因为其他代码引用了lst,并且您需要它看到更改,则仍然可以使用列表推导式,以及切片赋值:

>>> lst[:] = [v for i, v in enumerate(lst) if i not in indices]

在这里,我们正在创建一个新列表,然后用该新列表替换表示lst的整个内容的子切片。

0
lst = [2, 5, 7, 12, 13]

indexes = [3, 4]
to_del = object()

for index in indexes:
    lst[index] = to_del

for _ in indexes:
    lst.remove(to_del)

print(lst)

[2, 5, 7]

2
如果你想要一个安全的哨兵,你可以使用 to_del = object()。结果将永远不会与除它自己以外的任何对象比较(或哈希)相等。 - abarnert

0
你可以使用numpy索引来实现这个功能。

如果您能提供一个示例,那将更有帮助。 - AndreFeijo

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接