【问题标题】:Remove elements from a list according to indexes list efficiently根据索引列表有效地从列表中删除元素
【发布时间】:2016-03-09 12:47:59
【问题描述】:

我有两个非常大的整数列表:list1list2

list1 我有list2 的索引(有些是无效的),我需要从list2 中删除这些索引中的元素。

这是我的代码:

for index in list1:
    if index >= 0 and index < len(list2):  # verify index is valid
        list2.pop(index)

这是可行的,但我想要一个比这更快的解决方案。是否可以?也许使用numpy

【问题讨论】:

  • 您应该小心删除列表元素。我会导致很多问题。
  • 如果你可以牺牲内存来换取速度,你可以简单地创建一个带有理解的新列表。几乎总是最快的选择。
  • 为什么@MarkyPython有问题?
  • 比如说我希望遍历一个列表并删除所有少于 3 个字符的元素。如果我要在遍历列表时删除项目,那么每次我删除一个元素时,列表元素都会“向左移动”一个索引。因此,如果我在迭代期间删除索引 3 处的项目,那么在下一次迭代中,它将检查索引 4 处的项目。由于我们删除了项目 3 并导致元素向左“移位”,项目 4 变成了项目 3,现在当我们检查第 4 项时,它实际上是原始列表中的第 5 项,因此我们跳过了原始列表中的第 4 项。

标签: python arrays algorithm


【解决方案1】:

编辑:我刚刚注意到这个答案实际上与 Andy 所问的 inverse 完全相反,它删除了 list2 中索引为 list1。我将把它留在这里,以防有人尝试这样做遇到这个问题,但请注意,接下来是不是安迪查询的解决方案;为此,请查看 Salva 的答案。

原答案:

这是一个使用列表推导的解决方案(并且还避免在每次迭代时检查 list2 的长度):

list2_length = len(list2)

list2 = [list2[index] for index in list1 if index > 0 and index < list2_length]

【讨论】:

  • 正要发类似的东西。
【解决方案2】:

我假设您使用 有效 指的是时间复杂度。我们将nm 命名为list1list2 的大小。

您的解决方案似乎是最好的选择,但它没有给出 Python .pop() operates in O(m),所以它需要 O(n*m)。

如果没有更多信息,列表理解解决方案通常不是一个好主意,因为您应该测试索引是否在 list1 内,即 O(n)。所以解决方案:

filtered = [item for index, item in enumerate(list2) if index not in list1]

也可以在 O(n*m) 中执行。

但是如果 list1 是一个集合,您可以将 in 操作设为 O(1)。如果你这样做,这个集合的构造是 O(n):

ignore_indices = { index for index in list1 if 0 < index < len(list2) }

现在您可以构建另一个过滤列表,忽略该集合中的位置:

filtered = [item for index, item in enumerate(list2) if index not in ignore_indices]

这个运行 O(m) 所以最终的复杂度是 O(n+m)。

顺便说一句,我认为您的验证检查是0 &lt;= index &lt; len(list2),但我不确定您是否有意排除 0。

【讨论】:

  • 谢谢@Salva!而且,是的,我更新了我的问题以检查index &gt;= 0
猜你喜欢
  • 2018-12-31
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-04-18
  • 2017-08-31
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多