【问题标题】:Faster way of removing items from list从列表中删除项目的更快方法
【发布时间】:2016-06-17 00:54:46
【问题描述】:

我有一个长度约为 10M 的列表。每个索引都包含一个字典

比如说……

l = [{'id': 'y'}, {'id', 'x'}, {'id', 'z'} ... ]

我有另一个列表,其中包含我要删除的项目

m = ['y', 'z']

我试过了

l = [i for i in l if i['id'] not in m]

但正如预期的那样,O(n^3) 的运行时间并不惊人。 我的第二种方法是创建一个新字典来存储我希望删除的项目的索引:

temp = {'y': 0, 'z': 2, ... }

for i in range(0, len(temp)):
    del l[temp[m[-1]]]
    del m[-1]

这确实将执行时间提高了很多(对于 1M 的数据集,从大约一小时到几秒或几分钟)。但是由于我将索引存储在某个地方,因此使用的内存相当高

我的问题是:有没有更有效的方法可以在 O(n) 时间从大列表中删除项目,但又不占用太多内存?

【问题讨论】:

  • 你的列表排序了吗?就像你的例子一样?如果是这样,您可以使用二分搜索......这应该会提供显着的改进
  • @JoranBeasley 是的。该列表根据字典中的time 键进行排序
  • 这条线真的有用吗? l = [i for i in l if i not in m]i 是字典,m 是键列表。假设字典总是有一个条目,你不想做l = [i for i in l if i.keys()[0] not in m]。第二,为什么是O(n^3)?您只需遍历列表一次。如果该元素不在m 中,则保留它,否则跳过它。
  • @pushkin 啊,我的错,实际代码是正确的。我将编辑问题
  • m 变成一个集合,而不是一个列表。集合基于字典,这使它们可以更快地查找i['id'] not in m 测试,而不是检查列表中的成员资格。当您采用第二种方法时,您是如何获得要删除的项目的索引的,这不是需要很长时间吗?与 10M 的列表大小相比,大约有多少项要删除? - 1K? 1M? 990 万?

标签: python list memory time big-o


【解决方案1】:

我怀疑你会比:

s = set(m)
l = [i for i in l if i['id'] not in s]

这可能比创建一个循环并一次删除一个项目要快得多。通常在内存和速度之间进行权衡 - 这应该相当快,但在创建新列表时最多会使用两倍的内存。

警告:当我说“我怀疑你会比……好得多”时,我指的是标准 Python。像 Pandas 或 Numpy 这样的数值库在内存和时间方面可能会做得更好。

【讨论】:

  • 我刚刚在 3127 个字典的列表上尝试过(耗时 0.2462 秒),而制作索引字典耗时 0.0041 秒
  • @MonoShiro:好的,但是使用这种方法的总时间与您按索引删除的方法相比如何?
  • 你应该在理解之前只设置一次 m ......如果这更快将在很大程度上取决于 m 的大小......如果 m 中只有 2 或 3 个元素,这可能会几乎没有改善
  • @Gerrat 修复后运行时间提高到 0.00399 :)
  • 我能想到的唯一改进是使用生成器表达式 ((i for i in ...)) 或生成器函数 (for i in l: if ...: yield i) 一次生成一个输出列表项。如果他们发现他们不需要所有数据,这将允许以后对输出的任何使用提前“退出”,尽管在需要整个列表的情况下它不会有帮助。
【解决方案2】:

如果您只能将要删除的索引存储在列表 temp 中

temp = [0,2,...]

那么这可以更快地工作

np.delete(l,temp)

【讨论】:

  • 这是目前最快的(0.00199 秒)。但这确实需要您先获取索引...
  • 如果您要按索引从列表中删除任意项目,请按 reverse 顺序对这些索引进行排序。这将最大限度地减少无用的“向左滑动”操作......尽管仍然会有很多。
猜你喜欢
  • 2010-11-23
  • 2011-08-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-12-20
  • 1970-01-01
  • 2017-05-09
  • 1970-01-01
相关资源
最近更新 更多