更快的Python列表推导式

4

我有一段代码在我的项目中需要运行成千上万次:

def resample(freq, data):
    output = []
    for i, elem in enumerate(freq):
        for _ in range(elem):
            output.append(data[i])
    return output

例如:resample([1,2,3], ['a', 'b', 'c']) => ['a', 'b', 'b', 'c', 'c', 'c']

我希望尽可能提高这个方法的速度。使用列表推导似乎可以更快。我尝试过以下代码:

def resample(freq, data):
   return [item for sublist in [[data[i]]*elem for i, elem in enumerate(frequencies)] for item in sublist]

这段代码很丑陋,而且速度慢,因为它先构建列表,然后将其展平。有没有一种用单行列表推导式快速完成的方法?或者使用numpy做些什么?

提前感谢!

编辑:答案不一定要消除嵌套循环,最快的代码是最好的。


2
列表推导式并不比等价的for循环更快,因为它们执行的操作完全相同。 - Daniel Roseman
你在谈论什么样的输入?如果freq中的数字很大,那么在单个循环中使用extend可能比append更好。 - John Coleman
我不同意关闭@jonrsharpe。它不是那个问题的重复。 - Bharel
是的,我也不同意关闭。 - nosklo
如果您正在尝试对数据进行频率加权处理,请注意 numpypandas 可以直接处理权重,例如计算平均值 https://docs.scipy.org/doc/numpy/reference/generated/numpy.average.html - Stuart
显示剩余4条评论
3个回答

5
我强烈建议使用生成器,如下所示:
from itertools import repeat, chain
def resample(freq, data):
    return chain.from_iterable(map(repeat, data, freq))

这可能是最快的方法 - map()repeat()chain.from_iterable()都是用C实现的,因此你无法得到更好的性能。
至于简单解释: repeat(i, n) 返回一个迭代器,重复一个项目 i n 次。 map(repeat, data, freq) 返回一个迭代器,每次在datafreq中的元素上调用repeat()。基本上是返回repeat()迭代器的迭代器。 chain.from_iterable() 将迭代器的迭代器展平以返回最终项。
没有创建列表,因此没有开销,并且额外的好处是 - 你可以使用任何类型的数据,而不仅仅是一个字符字符串。
虽然我不建议这样做,但你可以将它转换成list(),像这样:
result = list(resample([1,2,3], ['a','b','c']))

一些快速的测试似乎证实了这是迄今为止最快的答案。 - anonymoose

2
import itertools
def resample(freq, data):
    return itertools.chain.from_iterable([el]*n for el, n in zip(data, freq))

除了更快之外,这种方法还有懒加载的优点,它返回一个生成器,并且元素是逐步生成的。

2
不需要创建列表,只需使用嵌套循环即可:
[e for i, e in enumerate(data) for j in range(freq[i])]

# ['a', 'b', 'b', 'c', 'c', 'c']

您可以通过删除括号来轻松实现这种懒惰方式:
(e for i, e in enumerate(data) for j in range(freq[i]))

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