【问题标题】:Optimal List Comprehension (Filtering Existing List)最优列表理解(过滤现有列表)
【发布时间】:2019-03-29 13:31:04
【问题描述】:

我有一个[index:boolean] 形式的大列表(1e8+ 个条目)。我想找到为真值的索引。 在这项任务中的表现至关重要。

目前从我在 Python 3.7.2 中可以看出,执行此操作的最佳方法是使用如下列表推导:

return [i for i, j in enumerate(numbers) if j]

我还尝试了以下方法(尽管它似乎只是早期 Python 版本的首选方法):

return list(filter(lambda a: a, numbers))

第二种方法比第一种方法慢约 25%。

目前,此操作大约需要 (0.8*x) 时间,而我的算法的实际逻辑部分需要 'x' 时间。 (例如,如果逻辑需要 10 秒,从列表中提取正值大约需要 8 秒)。我曾希望此操作会快得多。

【问题讨论】:

  • return [i for i, j in enumerate(numbers) if j] 这将创建一个列表并分配包含这些巨大数字的内存这是最有效的方法吗?
  • 您可以创建一个生成器表达式并根据需要懒惰地迭代它。
  • 您的 2 个示例不等效,为了便于理解,您使用 enumerate() 获取索引,使用 filter() 您只需提取真实的布尔值 - 您想要哪个?
  • 如果你有 2 个单独的列表,那么你也有一个 itertools.compress 类型的解决方案

标签: python list optimization micro-optimization


【解决方案1】:

在这个任务中的表现是最重要的

那么你应该考虑使用一个numpy数组:

import numpy as np
from random import choice
from timeit import Timer

bools = True, False
li = [choice(bools) for _ in range(int(1e8))]
arr = np.array(li)  

print(Timer(lambda: np.nonzero(arr)).repeat(1, 1))

输出

[0.4524359999999916]

这是0.4524359999999916 秒。

【讨论】:

  • 请注意,如果您不使用 numpy 来存储原始列表,则大部分速度提升将被转换为 np.array 所抵消。如果您需要将结果转换回列表(而不是从中产生的 np.array),情况会更糟。所以,为了从 numpy 中受益,你必须充分利用它。
猜你喜欢
  • 2022-11-29
  • 1970-01-01
  • 2011-03-02
  • 2013-12-02
  • 1970-01-01
  • 2012-10-27
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多