为什么'functools.reduce'和'itertools.chain.from_itertools'在嵌套列表合并时有不同的计算时间

时间:2018-03-07 09:28:02

标签: python python-3.x reduce itertools functools

有时您应该将嵌套合并到合并列表(它类似于np.flatten())。 当列表列表如下所示,你应该压扁它

a = [[j for j in range(0, 10)] for i in range(0, 10000)]

你有两种解决方案可以解决它。 itertools.chain.from_iterablefunctools.reduce

%timeit list(itertools.chain.from_iterable(a))
%timeit reduce(lambda x, y: x+y, a)

你认为哪一个比其他东西更快,速度更快?

itertools.chain.from_iterable快1000倍或更多(当列表的长度更大时)。

如果有人知道为什么会发生这种情况,请告诉我。

总是为你提供支持和帮助。

1 个答案:

答案 0 :(得分:4)

是的,因为列表连接(即使用+)是O(N)操作。当你这样做以逐步建立一个大小为N的列表时,它变为O(N 2 )。

相反,使用chain.from_iterable将使用list类型构造函数迭代最终列表中的所有N个项目,这将具有线性性能。

这就是为什么你不应该使用sum来展平列表(注意,reduce(lambda x, y: x+y,...)只是sum)。

注意,像这样展平嵌套列表的惯用方法是使用列表解析:

[x for sub in a for x in sub]

这是一种反模式,sum方法阻止您使用str个对象:

>>> sum(['here', 'is', 'some', 'strings'], '')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: sum() can't sum strings [use ''.join(seq) instead]

注意,您的reduce / sum方法相当于:

result = []
for sub in a:
    result = result + sub

这清楚地演示了循环中昂贵的+。注意,以下天真的方法实际上有O(N)行为而不是O(N 2 ):

result = []
for sub in a:
    result += sub

这是因为my_list += something相当于my_list.extend(something),而.extend(以及.append)已经摊销了常量时间行为,所以整体而言,它将是O( N)。