在评论中的讨论中这个问题 https://stackoverflow.com/questions/49630581/why-does-python-forbid-the-use-of-sum-with-strings有人提到,虽然连接字符串序列只需要''.join([str1, str2, ...])
,连接一系列列表就像list(itertools.chain(lst1, lst2, ...))
,尽管您也可以使用列表理解,例如[x for y in [lst1, lst2, ...] for x in y]
。令我惊讶的是,第一种方法始终比第二种方法快:
import random
import itertools
random.seed(100)
lsts = [[1] * random.randint(100, 1000) for i in range(1000)]
%timeit [x for y in lsts for x in y]
# 39.3 ms ± 436 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)
%timeit list(itertools.chain.from_iterable(lsts))
# 30.6 ms ± 866 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)
%timeit list(x for y in lsts for x in y) # Proposed in comments
# 62.5 ms ± 504 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)
# Loop-based methods proposed in the comments
%%timeit
a = []
for lst in lsts: a += lst
# 26.4 ms ± 634 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)
%%timeit
a = []
for lst in lsts: a.extend(lst)
# 26.7 ms ± 728 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)
虽然不是一个数量级的差异,但也不容忽视。我想知道情况如何,因为列表理解通常是解决给定问题的最快方法之一。起初我以为也许itertools.chain
对象会有一个len
认为list
构造函数可以用来预分配必要的内存,但事实并非如此(无法调用len
on itertools.chain
对象)。是一些定制的itertools.chain
-to-list
转换以某种方式发生或正在发生itertools.chain
利用其他机制?
如果相关的话,已在 Windows 10 x64 上的 Python 3.6.3 中进行测试。
EDIT:
毕竟调用似乎是最快的方法.extend
每个列表都有一个空列表,如建议的@zwer https://stackoverflow.com/users/7553525/zwer,可能是因为它适用于数据“块”,而不是基于每个元素。