以下是几种将多个列表附加在一起的方法的时间安排.
从最快到最慢显示它们.
Python 2.7(CPython-在Autodesk Maya 2014中运行),Windows 7 64位,Intel Core i7-37770K @ 3.5 GHz.
import timeit
def p_timeit_min(msg, expr_str, number, setup):
times = timeit.repeat(expr_str, number=number, setup=setup, repeat=3)
print( '{0:18} => {1:6.3f}'.format( msg, min(times) ))
n = 1000
timeit.repeat('1+1', number=10000) # "dummy" -- I'm in an environment where the first timeit call is erratic in performance.
setup_0 = '; import operator; L1 = list(range(n)); LL = [[10 * x + v for v in L1] for x in range(n)]'
p_timeit_min('map+extend 100', 'all = []; map(all.extend, LL)', number=n, setup='n = 100'+setup_0)
p_timeit_min('for+extend 100', """
all = []
for L in LL:
all.extend(L)
""", number=n, setup='n = 100'+setup_0)
p_timeit_min('extend 100', 'all = []; [all.extend(L) for L in LL]', number=n, setup='n = 100'+setup_0)
# reduce with [] initializer, to avoid need to wrap each L in list().
p_timeit_min('reduce+iadd 100 []', 'all = reduce(operator.iadd, LL, [])', number=n, setup='n = 100'+setup_0)
p_timeit_min('filter extend 100', 'all = []; filter( lambda x: False, iter(all.extend(L) for L in LL) )', number=n, setup='n = 100'+setup_0)
# WARNING: If remove "list()" wrapper around "list_", since this version isn't supplying a [] to accumulate the results, iadd will MODIFY the first element of LL, which may not be desired.
p_timeit_min('reduce+iadd 100 list()', 'all = reduce(operator.iadd, (list(list_) for list_ in LL))', number=n, setup='n = 100'+setup_0)
p_timeit_min('chain 100', 'all = list(itertools.chain(*LL))', number=n, setup='n = 100'+setup_0)
p_timeit_min('comprehension 100', 'all = [x for list_ in LL for x in list_]', number=n, setup='n = 100'+setup_0)
p_timeit_min('nested for append 100',
"""
all = []
for L in LL:
for x in L:
all.append(L)
""", number=n, setup='n = 100'+setup_0)
p_timeit_min('sum 100', 'all = sum(LL, [])', number=n, setup='n = 100'+setup_0)
p_timeit_min('map+extend 200', 'all = []; map(all.extend, LL)', number=n, setup='n = 200'+setup_0)
p_timeit_min('for+extend 200', """
all = []
for L in LL:
all.extend(L)
""", number=n, setup='n = 200'+setup_0)
p_timeit_min('extend 200', 'all = []; [all.extend(L) for L in LL]', number=n, setup='n = 200'+setup_0)
p_timeit_min('reduce+iadd 200 []', 'all = reduce(operator.iadd, LL, [])', number=n, setup='n = 200'+setup_0)
p_timeit_min('filter extend 200', 'all = []; filter( lambda x: False, iter(all.extend(L) for L in LL) )', number=n, setup='n = 200'+setup_0)
p_timeit_min('reduce+iadd 200 list()', 'all = reduce(operator.iadd, (list(list_) for list_ in LL))', number=n, setup='n = 200'+setup_0)
p_timeit_min('chain 200', 'all = list(itertools.chain(*LL))', number=n, setup='n = 200'+setup_0)
p_timeit_min('comprehension 200', 'all = [x for list_ in LL for x in list_]', number=n, setup='n = 200'+setup_0)
p_timeit_min('nested for append 200', """
all = []
for L in LL:
for x in L:
all.append(L)
""", number=n, setup='n = 200'+setup_0)
p_timeit_min('sum 200', 'all = sum(LL, [])', number=n, setup='n = 200'+setup_0)
输出:
map+extend 100 => 0.062
for+extend 100 => 0.064 ** within margin of error of first place, but slower on average
extend 100 => 0.066
reduce+iadd 100 [] => 0.063 ** see "200" case for reason this isn't placed higher in list.
filter extend 100 => 0.078
reduce+iadd 100 list=> 0.105 ** ignore this - use the better "reduce" above.
chain 100 => 0.127
comprehension 100 => 0.250
nested for append 100=>0.672
sum 100 => 1.424
对于O(n)阶算法,这些时间大约要长4倍-
“ 200”大小写是200 x 200,因此总元素数是“ 100”大小写的4倍.
观察:前5个变体的效果明显优于O(n)-长4倍的元素大约长3倍.这是因为每个列表更长.子列表数量增加了2倍:
map+extend 200 => 0.187
for+extend 200 => 0.190
extend 200 => 0.194
reduce+iadd 200 [] => 0.204
filter extend 200 => 0.217
reduce+iadd 200 list=> 0.311 ** ignore this - use the better "reduce" above.
chain 200 => 0.426
comprehension 200 => 0.931
nested for append 200=>2.676
sum 200 => 13.432
分析:如果每个列表包含许多元素,则前四个解决方案没有实质性差异.
嵌套列表推导所需的时间是最佳解决方案的4倍.另一方面,总共#个元素仍为O(n).在许多情况下,这是足够小的时间值的4倍,这无关紧要.
结论:如果这是您的情况对性能至关重要的因素,请使用list.extend进行任何循环,或使用reduce(operator.iadd,LL,[]).亚军的选择:itertools.chain的成本为2倍,或者[.. for .. for ..](嵌套列表理解)为4倍的成本.
CAVEAT:这是在Python 2.7上在一台机器上,在一个实现上的一项测试.
假设您有列表&您需要将结果作为列表;如果您有/需要序列/生成器/迭代器,那可能会改变余额(也许支持itertools.chain)?
TODO:包含许多SHORT列表的测试.