有时您应该将嵌套合并到合并列表(它类似于np.flatten()
)。
当列表列表如下所示,你应该压扁它
a = [[j for j in range(0, 10)] for i in range(0, 10000)]
你有两种解决方案可以解决它。 itertools.chain.from_iterable
和functools.reduce
。
%timeit list(itertools.chain.from_iterable(a))
%timeit reduce(lambda x, y: x+y, a)
你认为哪一个比其他东西更快,速度更快?
itertools.chain.from_iterable
快1000倍或更多(当列表的长度更大时)。
如果有人知道为什么会发生这种情况,请告诉我。
总是为你提供支持和帮助。
答案 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)。