Да, это плохо ...
==
означает, что ваши две ссылки на строки - это точно один и тот же объект. Возможно, вы слышали, что это так, потому что Java хранит личную таблицу (что она делает), но это не всегда так. Некоторые строки загружаются по-разному, построены из других строк и т. Д., Поэтому вы никогда не должны предполагать, что две одинаковые строки хранятся в одном месте.
Equals делает реальное сравнение для вас.
flat_list = [item for sublist in l for item in sublist]
, что означает:
for sublist in l:
for item in sublist:
flat_list.append(item)
быстрее, чем ярлыки, опубликованные до сих пор. (l
- список сгладить.)
Вот соответствующая функция:
flatten = lambda l: [item for sublist in l for item in sublist]
Для подтверждения, как всегда, вы можете использовать модуль timeit
в стандартная библиотека:
$ python -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 3: 143 usec per loop
$ python -mtimeit -s'l=[[1,2,3],[4,5,6], [7], [8,9]]*99' 'sum(l, [])'
1000 loops, best of 3: 969 usec per loop
$ python -mtimeit -s'l=[[1,2,3],[4,5,6], [7], [8,9]]*99' 'reduce(lambda x,y: x+y,l)'
1000 loops, best of 3: 1.1 msec per loop
Объяснение: ярлыки на основе +
(включая подразумеваемое использование в sum
), по необходимости, O(L**2)
, когда есть L подписок - как промежуточный список результатов продолжает увеличиваться, на каждом шаге создается новый объект промежуточного результирующего списка, и все элементы предыдущего промежуточного результата должны быть скопированы (а также несколько новых добавленных в конце). Таким образом (для простоты и без фактической потери общности) скажем, что у вас есть L подсписок из I предметов каждый: первые предметы I копируются взад и вперед L-1 раз, второй I - L-2 раза и т. Д .; общее количество экземпляров: I умножает сумму x для x от 1 до L, т. е. I * (L**2)/2
.
Понимание списка только генерирует один список, один раз и копирует каждый элемент (из его оригинальное место проживания в списке результатов) также ровно один раз.
Вы можете использовать numpy: flat_list = list(np.concatenate(list_of_list))
Это можно сделать, используя toolz.concat
или cytoolz.concat
(cythonized версия, которая в некоторых случаях может быть быстрее):
from cytoolz import concat
l = [[1, 2, 3], [4, 5, 6], [7], [8, 9]]
list(concat(l)) # or just `concat(l)` if one only wants to iterate over the items
На моем компьютере, в python 3.6, это похоже на время почти так же быстро, как [item for sublist in l for item in sublist]
(не считая времени импорта):
In [611]: %timeit L = [item for sublist in l for item in sublist]
695 ns ± 2.75 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)
In [612]: %timeit L = [item for sublist in l for item in sublist]
701 ns ± 5.5 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)
In [613]: %timeit L = list(concat(l))
719 ns ± 12 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)
In [614]: %timeit L = list(concat(l))
719 ns ± 22.9 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)
Версия toolz
действительно медленнее:
In [618]: from toolz import concat
In [619]: %timeit L = list(concat(l))
845 ns ± 29 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)
In [620]: %timeit L = list(concat(l))
833 ns ± 8.73 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)
Примечание. Ниже применимо к Python 3.3+, поскольку оно использует yield_from
. six
также является сторонним пакетом, хотя он стабилен. В качестве альтернативы вы можете использовать sys.version
.
В случае obj = [[1, 2,], [3, 4], [5, 6]]
все решения здесь хороши, включая понимание списка и itertools.chain.from_iterable
.
Однако рассмотрим этот несколько более сложный случай:
>>> obj = [[1, 2, 3], [4, 5], 6, 'abc', [7], [8, [9, 10]]]
Здесь есть несколько проблем:
6
- это просто скаляр; это не будет истребимым, поэтому приведенные выше маршруты не сработают здесь. 'abc'
, является технически итерируемым (все str
s). Тем не менее, чтение между строками немного, вы не хотите рассматривать его как таковое - вы хотите рассматривать его как один элемент. [8, [9, 10]]
сам является вложенным итерабельным , Исходное понимание списка и chain.from_iterable
извлекают только «1 уровень вниз». Вы можете исправить это следующим образом:
>>> from collections import Iterable
>>> from six import string_types
>>> def flatten(obj):
... for i in obj:
... if isinstance(i, Iterable) and not isinstance(i, string_types):
... yield from flatten(i)
... else:
... yield i
>>> list(flatten(obj))
[1, 2, 3, 4, 5, 6, 'abc', 7, 8, 9, 10]
Здесь вы проверяете, -элемент (1) повторяется с помощью Iterable
, ABC из itertools
, но также должен гарантировать, что (2) элемент не "string-like . "
yield from
на цикл for
, например. for x in flatten(i): yield x
– pylang
19 June 2018 в 19:06
Самое быстрое решение, которое я нашел (для большого списка в любом случае):
import numpy as np
#turn list into an array and flatten()
np.array(l).flatten()
Готово! Вы можете, конечно, включить его в список, выполнив список (l)
flat_list = []
for i in list_of_list:
flat_list+=i
Этот код также отлично работает, так как он просто расширяет список. Хотя это очень похоже, но только для цикла. Таким образом, он имеет меньшую сложность, чем добавление 2 для циклов.
Плохая особенность функции Anil выше заключается в том, что она требует от пользователя всегда вручную указывать второй аргумент как пустой список []
. Вместо этого это будет дефолт. Из-за того, как работают объекты Python, они должны быть установлены внутри функции, а не в аргументах.
Вот рабочая функция:
def list_flatten(l, a=None):
#check a
if a is None:
#initialize with empty list
a = []
for i in l:
if isinstance(i, list):
list_flatten(i, a)
else:
a.append(i)
return a
Тестирование:
In [2]: lst = [1, 2, [3], [[4]],[5,[6]]]
In [3]: lst
Out[3]: [1, 2, [3], [[4]], [5, [6]]]
In [11]: list_flatten(lst)
Out[11]: [1, 2, 3, 4, 5, 6]
Мне кажется, что мне проще:
>>> import numpy as np
>>> l = [[1, 2, 3], [4, 5, 6], [7], [8, 9]]
>>> print (np.concatenate(l))
[1 2 3 4 5 6 7 8 9]
import numpy as np l = [1, 2, 3] print (np.concatenate(l))
ValueError: zero-dimensional arrays cannot be concatenated
– Stas Bekman
23 June 2018 в 20:51
Я возвращаю свое заявление. сумма не является победителем. Хотя это быстрее, когда список невелик. Но производительность значительно ухудшается при использовании больших списков.
>>> timeit.Timer(
'[item for sublist in l for item in sublist]',
'l=[[1, 2, 3], [4, 5, 6, 7, 8], [1, 2, 3, 4, 5, 6, 7]] * 10000'
).timeit(100)
2.0440959930419922
Версия суммы все еще работает более минуты, и она еще не завершила обработку!
Для средних списков:
>>> timeit.Timer(
'[item for sublist in l for item in sublist]',
'l=[[1, 2, 3], [4, 5, 6, 7, 8], [1, 2, 3, 4, 5, 6, 7]] * 10'
).timeit()
20.126545906066895
>>> timeit.Timer(
'reduce(lambda x,y: x+y,l)',
'l=[[1, 2, 3], [4, 5, 6, 7, 8], [1, 2, 3, 4, 5, 6, 7]] * 10'
).timeit()
22.242258071899414
>>> timeit.Timer(
'sum(l, [])',
'l=[[1, 2, 3], [4, 5, 6, 7, 8], [1, 2, 3, 4, 5, 6, 7]] * 10'
).timeit()
16.449732065200806
Использование небольших списков и timeit: number = 1000000
>>> timeit.Timer(
'[item for sublist in l for item in sublist]',
'l=[[1, 2, 3], [4, 5, 6, 7, 8], [1, 2, 3, 4, 5, 6, 7]]'
).timeit()
2.4598159790039062
>>> timeit.Timer(
'reduce(lambda x,y: x+y,l)',
'l=[[1, 2, 3], [4, 5, 6, 7, 8], [1, 2, 3, 4, 5, 6, 7]]'
).timeit()
1.5289170742034912
>>> timeit.Timer(
'sum(l, [])',
'l=[[1, 2, 3], [4, 5, 6, 7, 8], [1, 2, 3, 4, 5, 6, 7]]'
).timeit()
1.0598428249359131
matplotlib.cbook.flatten()
будет работать для вложенных списков, даже если они гнездятся более глубоко, чем пример.
import matplotlib
l = [[1, 2, 3], [4, 5, 6], [7], [8, 9]]
print(list(matplotlib.cbook.flatten(l)))
l2 = [[1, 2, 3], [4, 5, 6], [7], [8, [9, 10, [11, 12, [13]]]]]
print list(matplotlib.cbook.flatten(l2))
Результат:
[1, 2, 3, 4, 5, 6, 7, 8, 9]
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13]
Это на 18 раз быстрее, чем подчеркивание. _.flatten:
Average time over 1000 trials of matplotlib.cbook.flatten: 2.55e-05 sec
Average time over 1000 trials of underscore._.flatten: 4.63e-04 sec
(time for underscore._)/(time for matplotlib.cbook) = 18.1233394636
def flatten(alist):
if alist == []:
return []
elif type(alist) is not list:
return [alist]
else:
return flatten(alist[0]) + flatten(alist[1:])
Вы можете избежать рекурсивных вызовов в стек, используя фактическую структуру данных стека довольно просто.
alist = [1,[1,2],[1,2,[4,5,6],3, "33"]]
newlist = []
while len(alist) > 0 :
templist = alist.pop()
if type(templist) == type(list()) :
while len(templist) > 0 :
temp = templist.pop()
if type(temp) == type(list()) :
for x in temp :
templist.append(x)
else :
newlist.append(temp)
else :
newlist.append(templist)
print(list(reversed(newlist)))
def flatten(l, a):
for i in l:
if isinstance(i, list):
flatten(i, a)
else:
a.append(i)
return a
print(flatten([[[1, [1,1, [3, [4,5,]]]], 2, 3], [4, 5],6], []))
# [1, 1, 1, 3, 4, 5, 2, 3, 4, 5, 6]
a=[]
: >>> flatten([[1,2,3],[4,5,6]]) [1, 2, 3, 4, 5, 6] >>> flatten([[1,2,3],[4,5,6]]) [1, 2, 3, 4, 5, 6, 1, 2, 3, 4, 5, 6]
– Jeff
6 November 2016 в 23:52
Причина, по которой ваша функция не работает: расширение расширяет массив на месте и не возвращает его. Вы можете вернуть x из лямбда, используя некоторый трюк:
reduce(lambda x,y: x.extend(y) or x, l)
Примечание: расширение более эффективно, чем + в списках.
Недавно я столкнулся с ситуацией, когда у меня было сочетание строк и числовых данных в подсписках, таких как
test = ['591212948',
['special', 'assoc', 'of', 'Chicago', 'Jon', 'Doe'],
['Jon'],
['Doe'],
['fl'],
92001,
555555555,
'hello',
['hello2', 'a'],
'b',
['hello33', ['z', 'w'], 'b']]
, где методы, подобные flat_list = [item for sublist in test for item in sublist]
, не работали. Итак, я придумал следующее решение для 1+ уровня подписок
def concatList(data):
results = []
for rec in data:
if type(rec) == list:
results += rec
results = concatList(results)
else:
results.append(rec)
return results
И результат
In [38]: concatList(test)
Out[38]:
Out[60]:
['591212948',
'special',
'assoc',
'of',
'Chicago',
'Jon',
'Doe',
'Jon',
'Doe',
'fl',
92001,
555555555,
'hello',
'hello2',
'a',
'b',
'hello33',
'z',
'w',
'b']
Очищено пример @Deleet
from collections import Iterable
def flatten(l, a=[]):
for i in l:
if isinstance(i, Iterable):
flatten(i, a)
else:
a.append(i)
return a
daList = [[1,4],[5,6],[23,22,234,2],[2], [ [[1,2],[1,2]],[[11,2],[11,22]] ] ]
print(flatten(daList))
Пример: https://repl.it/G8mb/0
a
. Mutable default args имеют побочные эффекты и их часто избегают в Python. У этой ссылки есть решение. Приветствия.
– pylang
25 March 2017 в 19:22
Можно также использовать FlatPage flatp :
import numpy as np
list(np.array(l).flat)
Редактировать 11/02/2016: Работает только в том случае, если подписи имеют одинаковые размеры.
Кажется, что с operator.add
возникает путаница! Когда вы добавляете два списка вместе, правильным термином для этого является concat
, а не добавлять. operator.concat
- это то, что вам нужно использовать.
Если вы думаете о функциональности, это так же просто, как это ::
>>> list2d = ((1,2,3),(4,5,6), (7,), (8,9))
>>> reduce(operator.concat, list2d)
(1, 2, 3, 4, 5, 6, 7, 8, 9)
. Вы видите, что уменьшают уважение к типу последовательности, поэтому, когда вы поставляете кортеж, вы возвращаете кортеж. давайте попробуем со списком ::
>>> list2d = [[1,2,3],[4,5,6], [7], [8,9]]
>>> reduce(operator.concat, list2d)
[1, 2, 3, 4, 5, 6, 7, 8, 9]
Aha, вы получите список.
Как насчет производительности ::
>>> list2d = [[1,2,3],[4,5,6], [7], [8,9]]
>>> %timeit list(itertools.chain.from_iterable(list2d))
1000000 loops, best of 3: 1.36 µs per loop
from_iterable довольно быстро! Но это не сравнимо с уменьшением с concat.
>>> list2d = ((1,2,3),(4,5,6), (7,), (8,9))
>>> %timeit reduce(operator.concat, list2d)
1000000 loops, best of 3: 492 ns per loop
Почему вы используете расширение?
reduce(lambda x, y: x+y, l)
Это должно работать нормально.
Если вы готовы отказаться от крошечной скорости для более чистого вида, вы можете использовать numpy.concatenate().tolist()
или numpy.concatenate().ravel().tolist()
:
import numpy
l = [[1, 2, 3], [4, 5, 6], [7], [8, 9]] * 99
%timeit numpy.concatenate(l).ravel().tolist()
1000 loops, best of 3: 313 µs per loop
%timeit numpy.concatenate(l).tolist()
1000 loops, best of 3: 312 µs per loop
%timeit [item for sublist in l for item in sublist]
1000 loops, best of 3: 31.5 µs per loop
Вы можете узнать больше здесь, в docs numpy.concatenate и numpy.ravel
Если вы хотите сгладить структуру данных, где вы не знаете, насколько глубоко она вложена, вы можете использовать iteration_utilities.deepflatten
1
>>> from iteration_utilities import deepflatten
>>> l = [[1, 2, 3], [4, 5, 6], [7], [8, 9]]
>>> list(deepflatten(l, depth=1))
[1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> l = [[1, 2, 3], [4, [5, 6]], 7, [8, 9]]
>>> list(deepflatten(l))
[1, 2, 3, 4, 5, 6, 7, 8, 9]
Это генератор, поэтому вам нужно передать результат в list
или явно перебрать его.
Чтобы сгладить только один уровень, и если каждый из элементов сам итерабельен, вы также можете использовать iteration_utilities.flatten
, который сам по себе является лишь тонкой оболочкой вокруг itertools.chain.from_iterable
:
>>> from iteration_utilities import flatten
>>> l = [[1, 2, 3], [4, 5, 6], [7], [8, 9]]
>>> list(flatten(l))
[1, 2, 3, 4, 5, 6, 7, 8, 9]
Просто добавьте некоторые тайминги (на основании ответа Нико Шломера, 't включить функцию, представленную в этом ответе):
Это график лог-журнала для размещения для огромного диапазона значений, охватываемых. Для качественных рассуждений: лучше нижний.
Результаты показывают, что если итерабель содержит только несколько внутренних итераций, тогда sum
будет самым быстрым, однако для длинных итераций только itertools.chain.from_iterable
, iteration_utilities.deepflatten
или вложенное понимание имеет разумную производительность, причем itertools.chain.from_iterable
является самым быстрым (как уже заметил Нико Шломер).
from itertools import chain
from functools import reduce
from collections import Iterable # or from collections.abc import Iterable
import operator
from iteration_utilities import deepflatten
def nested_list_comprehension(lsts):
return [item for sublist in lsts for item in sublist]
def itertools_chain_from_iterable(lsts):
return list(chain.from_iterable(lsts))
def pythons_sum(lsts):
return sum(lsts, [])
def reduce_add(lsts):
return reduce(lambda x, y: x + y, lsts)
def pylangs_flatten(lsts):
return list(flatten(lsts))
def flatten(items):
"""Yield items from any nested iterable; see REF."""
for x in items:
if isinstance(x, Iterable) and not isinstance(x, (str, bytes)):
yield from flatten(x)
else:
yield x
def reduce_concat(lsts):
return reduce(operator.concat, lsts)
def iteration_utilities_deepflatten(lsts):
return list(deepflatten(lsts, depth=1))
from simple_benchmark import benchmark
b = benchmark(
[nested_list_comprehension, itertools_chain_from_iterable, pythons_sum, reduce_add,
pylangs_flatten, reduce_concat, iteration_utilities_deepflatten],
arguments={2**i: [[0]*5]*(2**i) for i in range(1, 13)},
argument_name='number of inner lists'
)
b.plot()
1 Отказ от ответственности: я являюсь автором этой библиотеки
sum
больше не работает с произвольными последовательностями, начиная с 0
, делая functools.reduce(operator.add, sequences)
заменой (мы не рады, что они удалили reduce
из встроенных?). Когда типы известны, возможно, быстрее использовать type.__add__
.
– Yann Vernier
14 May 2018 в 06:29
sum
. Вы знаете, какие версии Python перестали работать?
– MSeifert
15 May 2018 в 09:24
0
- это только начальное значение по умолчанию, поэтому оно работает, если вы используете начальный аргумент start , чтобы начать с пустого списка ... но он все еще содержит специальные строки и говорит мне использовать join. Он реализует foldl
вместо foldl1
. Эта же проблема появляется в версии 2.7.
– Yann Vernier
15 May 2018 в 09:31
Я тестировал большинство предлагаемых решений с помощью perfplot (мой собственный проект, по существу, обертка вокруг timeit
) и нашел
list(itertools.chain.from_iterable(a))
самым быстрым решением (если более 10 списков объединены).
Код для воспроизведения графика:
import functools
import itertools
import numpy
import operator
import perfplot
def forfor(a):
return [item for sublist in a for item in sublist]
def sum_brackets(a):
return sum(a, [])
def functools_reduce(a):
return functools.reduce(operator.concat, a)
def itertools_chain(a):
return list(itertools.chain.from_iterable(a))
def numpy_flat(a):
return list(numpy.array(a).flat)
def numpy_concatenate(a):
return list(numpy.concatenate(a))
perfplot.show(
setup=lambda n: [list(range(10))] * n,
kernels=[
forfor, sum_brackets, functools_reduce, itertools_chain, numpy_flat,
numpy_concatenate
],
n_range=[2**k for k in range(16)],
logx=True,
logy=True,
xlabel='num lists'
)
Это может быть не самый эффективный способ, но я решил поставить однострочный (фактически двухстрочный). Обе версии будут работать с произвольными иерархическими вложенными списками и будут использовать языковые возможности (Python3.5) и рекурсию.
def make_list_flat (l):
flist = []
flist.extend ([l]) if (type (l) is not list) else [flist.extend (make_list_flat (e)) for e in l]
return flist
a = [[1, 2], [[[[3, 4, 5], 6]]], 7, [8, [9, [10, 11], 12, [13, 14, [15, [[16, 17], 18]]]]]]
flist = make_list_flat(a)
print (flist)
Выход:
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18]
Это работает на глубине первый способ. Рекурсия идет до тех пор, пока не найдет элемент, не являющийся списком, затем расширяет локальную переменную flist
и затем возвращает ее родительскому элементу. Всякий раз, когда возвращается flist
, он расширяется до родительского flist
в понимании списка. Поэтому в корне возвращается плоский список.
Вышеописанное создает несколько локальных списков и возвращает их, которые используются для расширения списка родителя. Я думаю, что путь для этого может создать gloabl flist
, как показано ниже.
a = [[1, 2], [[[[3, 4, 5], 6]]], 7, [8, [9, [10, 11], 12, [13, 14, [15, [[16, 17], 18]]]]]]
flist = []
def make_list_flat (l):
flist.extend ([l]) if (type (l) is not list) else [make_list_flat (e) for e in l]
make_list_flat(a)
print (flist)
Выход снова
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18]
Хотя я не уверен в этом время об эффективности.
Рассмотрим установку пакета more_itertools
.
> pip install more_itertools
Он поставляется с реализацией для flatten
( source из рецептов itertools ):
import more_itertools
lst = [[1, 2, 3], [4, 5, 6], [7], [8, 9]]
list(more_itertools.flatten(lst))
# [1, 2, 3, 4, 5, 6, 7, 8, 9]
Начиная с версии 2.4 вы можете сгладить более сложные, вложенные итерации с помощью more_itertools.collapse
( источник , внесенный abarnet).
lst = [[1, 2, 3], [4, 5, 6], [7], [8, 9]]
list(more_itertools.collapse(lst))
# [1, 2, 3, 4, 5, 6, 7, 8, 9]
lst = [[1, 2, 3], [[4, 5, 6]], [[[7]]], 8, 9] # complex nesting
list(more_itertools.collapse(lst))
# [1, 2, 3, 4, 5, 6, 7, 8, 9]
more_itertools
среди других, обсуждавшихся в этом сообщении. Приветствия.
– pylang
25 March 2017 в 18:51
yield from
на python, узнав о yield *
в es2015.
– Triptych
14 April 2017 в 21:30
if isinstance(el, collections.Iterable) and not isinstance(el, (str, bytes)):
на поддержку строк.
– Jorge Leitão
13 May 2017 в 23:40
from functools import reduce #python 3
>>> l = [[1,2,3],[4,5,6], [7], [8,9]]
>>> reduce(lambda x,y: x+y,l)
[1, 2, 3, 4, 5, 6, 7, 8, 9]
Метод extend()
в вашем примере изменяет x
вместо того, чтобы возвращать полезное значение (которое ожидает reduce()
).
Более быстрый способ сделать версию reduce
be
>>> import operator
>>> l = [[1,2,3],[4,5,6], [7], [8,9]]
>>> reduce(operator.concat, l)
[1, 2, 3, 4, 5, 6, 7, 8, 9]
reduce(operator.add, l)
будет правильным способом сделать версию reduce
. Встроенные функции быстрее, чем lambdas.
– agf
24 September 2011 в 11:04
timeit.timeit('reduce(operator.add, l)', 'import operator; l=[[1, 2, 3], [4, 5, 6, 7, 8], [1, 2, 3, 4, 5, 6, 7]]', number=10000)
0.017956018447875977 * timeit.timeit('reduce(lambda x, y: x+y, l)', 'import operator; l=[[1, 2, 3], [4, 5, 6, 7, 8], [1, 2, 3, 4, 5, 6, 7]]', number=10000)
0.025218963623046875
– lukmdo
21 March 2012 в 00:13
integers
. Но что, если список содержит string
?
– Freddy
11 September 2015 в 07:16
operator.add
работает одинаково хорошо для обоих списков целых чисел и списков строк.
– Greg Hewgill
11 September 2015 в 07:38
Вы можете использовать itertools.chain()
:
>>> import itertools
>>> list2d = [[1,2,3],[4,5,6], [7], [8,9]]
>>> merged = list(itertools.chain(*list2d))
или, на Python> = 2.6, использовать itertools.chain.from_iterable()
, который не требуется распаковать список:
>>> import itertools
>>> list2d = [[1,2,3],[4,5,6], [7], [8,9]]
>>> merged = list(itertools.chain.from_iterable(list2d))
Этот подход, возможно, более читабельен, чем [item for sublist in l for item in sublist]
, и, похоже, работает быстрее:
[me@home]$ python -mtimeit -s'l=[[1,2,3],[4,5,6], [7], [8,9]]*99;import itertools' 'list(itertools.chain.from_iterable(l))'
10000 loops, best of 3: 24.2 usec per loop
[me@home]$ python -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 3: 45.2 usec per loop
[me@home]$ python -mtimeit -s'l=[[1,2,3],[4,5,6], [7], [8,9]]*99' 'sum(l, [])'
1000 loops, best of 3: 488 usec per loop
[me@home]$ python -mtimeit -s'l=[[1,2,3],[4,5,6], [7], [8,9]]*99' 'reduce(lambda x,y: x+y,l)'
1000 loops, best of 3: 522 usec per loop
[me@home]$ python --version
Python 2.7.3
*
- сложная вещь, которая делает chain
менее понятным, чем понимание списка. Вы должны знать, что цепочка соединяется вместе только итерами, передаваемыми как параметры, и * заставляет список верхнего уровня расширяться в параметры, поэтому chain
объединяет все эти итерации, но не спускается дальше. Я думаю, что это делает понимание более читаемым, чем использование цепочки в этом случае.
– Tim Dierks
3 September 2014 в 15:13
for
, который несколько раз append
станет более очевидным.
– ShadowRanger
12 November 2015 в 21:26
['abcde_', ['_abcde', ['e_abcd', ['de_abc', ['cde_ab', ['bcde_a']]]]]]
– Aymon Fournier
7 December 2015 в 20:24
Другой необычный подход, который работает для гетеро- и однородных списков целых чисел:
def unusual_flatten(some_list: list) -> list:
cleaned_list = str(some_list).replace(("["), "").replace("]", "").split(",")
return [int(item) for item in cleaned_list]
Применение в списке примеров ...
l = [[1, 2, 3], [4, 5, 6], [7], [8, 9], 10]
unusual_flatten(l)
Результат:
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
wierd_list = [[1, 2, 3], [4, 5, 6], [7], [8, 9], 10]
& gt; & gt; nice_list=[1, 2, 3, 4, 5, 6, 7, 8, 9, 1, 0]
– tharndt
11 January 2018 в 09:17
flat_list = [int(e.replace('[','').replace(']','')) for e in str(deep_list).split(',')]
– tharndt
11 January 2018 в 09:32
[int(e.strip('[ ]')) for e in str(deep_list).split(',')]
. Но я предлагаю придерживаться предложения Деле для реальных случаев использования. Он не содержит преобразований хакерского типа, он быстрее и универсален, потому что он, естественно, также обрабатывает списки со смешанными типами.
– Darkonaut
11 January 2018 в 17:31
Примечание автора: Это неэффективно. Но весело, потому что монады потрясающие. Это не подходит для производственного кода Python.
>>> sum(l, [])
[1, 2, 3, 4, 5, 6, 7, 8, 9]
Это просто суммирует элементы итерабельности, переданные в первом аргументе, обрабатывая второй аргумент как начальное значение суммы (если не указано, 0
вместо этого этот случай даст вам ошибку).
Поскольку вы суммируете вложенные списки, вы фактически получаете [1,3]+[2,4]
в результате sum([[1,3],[2,4]],[])
, который равен [1,3,2,4]
.
Обратите внимание, что работает только в списках списков. Для списков списков списков вам понадобится другое решение.
Monoid
, что является одной из самых удобных абстракций для мышления о работе +
в общем смысле (не ограничиваясь числами только). Поэтому этот ответ заслуживает +1 от меня за (правильное) обращение с списками как моноид. Производительность имеет отношение, хотя ... i>
– ulidtko
3 December 2014 в 11:35
Простой код для вентилятора пакета underscore.py
from underscore import _
_.flatten([[1, 2, 3], [4, 5, 6], [7], [8, 9]])
# [1, 2, 3, 4, 5, 6, 7, 8, 9]
Он решает все проблемы с плоским (ни один элемент списка или сложная вложенность)
from underscore import _
# 1 is none list item
# [2, [3]] is complex nesting
_.flatten([1, [2, [3]], [4, 5, 6], [7], [8, 9]])
# [1, 2, 3, 4, 5, 6, 7, 8, 9]
Вы можете установить underscore.py
с помощью pip
pip install underscore.py
Вот общий подход, который применяется к числам, строкам, вложенным спискам и смешанным контейнерам.
Код
from collections import Iterable
def flatten(items):
"""Yield items from any nested iterable; see Reference."""
for x in items:
if isinstance(x, Iterable) and not isinstance(x, (str, bytes)):
for sub_x in flatten(x):
yield sub_x
else:
yield x
Примечание: в Python 3, yield from flatten(x)
может заменить for sub_x in flatten(x): yield sub_x
Демо
lst = [[1, 2, 3], [4, 5, 6], [7], [8, 9]]
list(flatten(lst)) # nested lists
# [1, 2, 3, 4, 5, 6, 7, 8, 9]
mixed = [[1, [2]], (3, 4, {5, 6}, 7), 8, "9"] # numbers, strs, nested & mixed
list(flatten(mixed))
# [1, 2, 3, 4, 5, 6, 7, 8, '9']
Ссылка
more_itertools
среди других, обсуждавшихся в этом сообщении. Приветствия.
– pylang
25 March 2017 в 18:51
yield from
на python, узнав о yield *
в es2015.
– Triptych
14 April 2017 в 21:30
if isinstance(el, collections.Iterable) and not isinstance(el, (str, bytes)):
на поддержку строк.
– Jorge Leitão
13 May 2017 в 23:40
itertools.chain.from_iterable
:$ python -mtimeit -s'from itertools import chain; l=[[1,2,3],[4,5,6], [7], [8,9]]*99' 'list(chain.from_iterable(l))'
. Он работает чуть более, чем в два раза быстрее, чем понимание вложенного списка, которое является самым быстрым из приведенных здесь альтернатив. – intuited 15 October 2010 в 02:21list()
, чтобы реализовать итератор в списке. – intuited 20 May 2012 в 23:56list(itertools.chain.from_iterable(l))
лучше всего - как замечено в других комментариях и ответе Шона. – Alex Martelli 4 January 2015 в 16:40