Вопрос-Ответ

Flatten an irregular (arbitrarily nested) list of lists

Сгладить нерегулярный (произвольно вложенный) список списков

Да, я знаю, что эта тема рассматривалась ранее:

но, насколько я знаю, все решения, кроме одного, терпят неудачу в списке типа [[[1, 2, 3], [4, 5]], 6], где находится желаемый результат [1, 2, 3, 4, 5, 6] (или, возможно, даже лучше, итератор).

Единственное решение, которое я видел, которое работает для произвольной вложенности, найдено в этом вопросе:

def flatten(x):
result = []
for el in x:
if hasattr(el, "__iter__") and not isinstance(el, basestring):
result.extend(flatten(el))
else:
result.append(el)
return result

Это лучший подход? Я что-то упустил? Есть проблемы?

Переведено автоматически
Ответ 1

Использование функций генератора может облегчить чтение вашего примера и повысить производительность.

Python 2

Используя Iterable ABC, добавленный в 2.6:

from collections import Iterable

def flatten(xs):
for x in xs:
if isinstance(x, Iterable) and not isinstance(x, basestring):
for item in flatten(x):
yield item
else:
yield x

Python 3

В Python 3 basestring больше нет, но кортеж (str, bytes) дает тот же эффект. Кроме того, yield from оператор возвращает элемент из генератора по одному за раз.

from collections.abc import Iterable

def flatten(xs):
for x in xs:
if isinstance(x, Iterable) and not isinstance(x, (str, bytes)):
yield from flatten(x)
else:
yield x
Ответ 2

Мое решение:

import collections


def flatten(x):
if isinstance(x, collections.Iterable):
return [a for i in x for a in flatten(i)]
else:
return [x]

Немного более лаконично, но практически то же самое.

Ответ 3

Генератор, использующий рекурсию и утиный ввод (обновлено для Python 3):

def flatten(L):
for item in L:
try:
yield from flatten(item)
except TypeError:
yield item

list(flatten([[[1, 2, 3], [4, 5]], 6]))
>>>[1, 2, 3, 4, 5, 6]
Ответ 4

Вот моя функциональная версия recursive flatten, которая обрабатывает как кортежи, так и списки и позволяет вводить любое сочетание позиционных аргументов. Возвращает генератор, который выдает всю последовательность по порядку, аргумент за аргументом:

flatten = lambda *n: (e for a in n
for e in (flatten(*a) if isinstance(a, (tuple, list)) else (a,)))

Использование:

l1 = ['a', ['b', ('c', 'd')]]
l2 = [0, 1, (2, 3), [[4, 5, (6, 7, (8,), [9]), 10]], (11,)]
print list(flatten(l1, -2, -1, l2))
['a', 'b', 'c', 'd', -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]
python list