В контексте обсуждения в комментариях к этому вопросу было упомянуто, что при объединении последовательности строк просто берется ''.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
на объектах itertools.chain
). Является ли какое-то itertools.chain
преобразование itertools.chain
list
каким-то образом или itertools.chain
использует какой-то другой механизм?
Протестировано в Python 3.6.3 на Windows 10 x64, если это актуально.
РЕДАКТИРОВАТЬ:
Кажется, что самый быстрый метод - это вызов. .extend
пустой список с каждым списком, как это было предложено @zwer, вероятно, потому, что он работает с "кусками" данных, а не на основе каждого элемента.