def flattenList(toFlatten):
final=[]
for el in toFlatten:
if isinstance(el, list):
final.extend(flattenList(el))
else:
final.append(el)
return final
Когда я не знаю, как глубоко списки вложат, это - единственный способ, которым я могу думать, чтобы сделать это.
Вот еще один вариант (хотя может быть что-то более чистое, чем проверка типов, например, проверка, является ли что-то итерируемым и, следовательно, не "атомом"):
def flatten(lst):
if not isinstance(lst,list):
return [lst]
else:
return reduce(lambda x,y:x+y,[flatten(x) for x in lst],[])
Он основан на чем-то схемоподобном.
Этот ответ объясняет, почему вы не хотите использовать reduce
для этого в Python.
Рассмотрим фрагмент
reduce(operator.add, [[1], [2], [3], [4], [5]])
Что это должно делать?
[1] + [2] => [1, 2]
[1, 2] + [3] => This makes a new list, having to go over 1, then 2, then 3. [1, 2, 3]
[1, 2, 3] + [4] => This has to copy the 1, 2, and 3 and then put 4 in the new list
[1, 2, 3, 4] + [5] => The length of stuff I have to copy gets bigger each time!
Такого квадратичного поведения можно полностью избежать: исходное решение (и любое количество других решений) не формирует эти промежуточные этапы копирования.
Вам следует избегать проверки типов в Python. В данном случае это означает отказ от произвольно вложенных структур, в которых вы различаете по типу. Вы можете создать свой собственный тип узла, который вы можете перемещать методами , отличными , кроме проверки типов, например, глядя на определенный атрибут.
Для сведения одного уровня или ровно n уровней см. itertools.chain.from_iterable
.
Я не знаю, что вы подразумеваете под «функциональным». Этот код довольно функциональный: он использует рекурсию (не к его чести!) И не изменяет свой аргумент. (Строго говоря, он действительно использует изменяемое состояние для построения списка, но это именно то, как вы это делаете в Python.
Я полагаю, что еще одним функциональным атрибутом будет ленивая оценка. Вы могли бы реализовать это таким образом
def flatten ( toFlatten):
для элемента в toFlatten:
if isinstance (item, list): # Ewww, typchecking
для подэлемента в flatten (item): # они рассматривают возможность добавления {{ 1}} yield subitem # "yield from" на язык
#, чтобы задать синтаксис этого шаблона
else:
yield item
Рекурсия очень ограничена в Python (по крайней мере, во всех его основных реализациях), и его обычно следует избегать для произвольной глубины. Вполне возможно переписать это (и весь рекурсивный код), чтобы использовать итерацию, которая сделает его более масштабируемым (и менее функциональным, что это хорошая вещь в Python, которая не особенно подходит для FP.)