Наиболее популярные решения здесь обычно выравнивают только один "уровень" вложенного списка. Смотрите в разделе Сглаживание нерегулярного (произвольно вложенного) списка списков для решений, которые полностью сглаживают глубоко вложенную структуру (рекурсивно, в общем случае).
Переведено автоматически
Ответ 1
Список списков с именем xss может быть уменьшен с помощью понимания списка:
flat_list = [ x for xs in xss for x in xs ]
Вышесказанное эквивалентно:
flat_list = []
for xs in xss: for x in xs: flat_list.append(x)
Вот соответствующая функция:
defflatten(xss): return [x for xs in xss for x in xs]
Это самый быстрый метод. В качестве доказательства, используя timeit модуль в стандартной библиотеке, мы видим:
$ python -mtimeit -s'xss=[[1,2,3],[4,5,6],[7],[8,9]]*99''[x for xs in xss for x in xs]' 10000 loops, best of 3: 143 usec per loop
$ python -mtimeit -s'xss=[[1,2,3],[4,5,6],[7],[8,9]]*99''sum(xss, [])' 1000 loops, best of 3: 969 usec per loop
$ python -mtimeit -s'xss=[[1,2,3],[4,5,6],[7],[8,9]]*99''reduce(lambda xs, ys: xs + ys, xss)' 1000 loops, best of 3: 1.1 msec per loop
Объяснение: методы, основанные на + (включая подразумеваемое использование в sum), необходимы, O(L**2) когда есть L подсписков - поскольку список промежуточных результатов становится длиннее, на каждом шаге выделяется новый объект списка промежуточных результатов, и все элементы в предыдущем промежуточном результате должны быть скопированы (а также добавлено несколько новых в конце). Итак, для простоты и без фактической потери общности предположим, что у вас есть L подсписков по M элементов в каждом: первые M элементов копируются туда и обратно L-1 раз, вторые M элементов L-2 раз и так далее; общее количество копий в M раз больше суммы x для x от 1 до L без учета, т.е. M * (L**2)/2.
Понимание списка генерирует один список только один раз и копирует каждый элемент (из его первоначального места жительства в результирующий список) также ровно один раз.
Этот подход, возможно, более удобочитаем, чем [item for sublist in l for item in sublist], и, похоже, также быстрее:
$ python3 -mtimeit -s'l=[[1,2,3],[4,5,6], [7], [8,9]]*99;import itertools''list(itertools.chain.from_iterable(l))' 20000 loops, best of 5: 10.8 usec per loop $ python3 -mtimeit -s'l=[[1,2,3],[4,5,6], [7], [8,9]]*99''[item for sublist in l for item in sublist]' 10000 loops, best of 5: 21.7 usec per loop $ python3 -mtimeit -s'l=[[1,2,3],[4,5,6], [7], [8,9]]*99''sum(l, [])' 1000 loops, best of 5: 258 usec per loop $ python3 -mtimeit -s'l=[[1,2,3],[4,5,6], [7], [8,9]]*99;from functools import reduce''reduce(lambda x,y: x+y,l)' 1000 loops, best of 5: 292 usec per loop $ python3 --version Python 3.7.5rc1
Ответ 3
Примечание от автора: Это очень неэффективно. Но весело, потому что моноиды потрясающие.
sum суммирует элементы итерируемого xss и использует второй аргумент в качестве начального значения [] для суммы. (Начальное значение по умолчанию - 0, которое не является списком.)
Поскольку вы суммируете вложенные списки, вы фактически получаете [1,3]+[2,4] в результате sum([[1,3],[2,4]],[]), что равно [1,3,2,4].
Обратите внимание, что это работает только со списками списков. Для списков списков списков списков вам понадобится другое решение.
Ответ 4
Я протестировал большинство предлагаемых решений с помощью perfplot (мой любимый проект, по сути, оболочка вокруг timeit) и нашел
import functools import operator functools.reduce(operator.iconcat, a, [])
это самое быстрое решение, как при объединении множества небольших, так и нескольких длинных списков. (operator.iadd одинаково быстро.)
Более простой и приемлемый вариант - это
out = [] for sublist in a: out.extend(sublist)
Если количество подсписков велико, это работает немного хуже, чем приведенное выше предложение.
Код для воспроизведения графика:
import functools import itertools import operator
import numpy as np import perfplot
defforfor(a): return [item for sublist in a for item in sublist]
defsum_brackets(a): returnsum(a, [])
deffunctools_reduce(a): return functools.reduce(operator.concat, a)
deffunctools_reduce_iconcat(a): return functools.reduce(operator.iconcat, a, [])