Существует ли функциональный способ сделать это?

def flattenList(toFlatten):
 final=[]
 for el in toFlatten:
  if isinstance(el, list):
   final.extend(flattenList(el))
  else:
   final.append(el)
 return final

Когда я не знаю, как глубоко списки вложат, это - единственный способ, которым я могу думать, чтобы сделать это.

5
задан Mat Nadrofsky 18 March 2010 в 18:32
поделиться

4 ответа

Вот еще один вариант (хотя может быть что-то более чистое, чем проверка типов, например, проверка, является ли что-то итерируемым и, следовательно, не "атомом"):

def flatten(lst):
    if not isinstance(lst,list):
        return [lst]
    else:
        return reduce(lambda x,y:x+y,[flatten(x) for x in lst],[])

Он основан на чем-то схемоподобном.

1
ответ дан 18 December 2019 в 14:44
поделиться

Этот ответ объясняет, почему вы не хотите использовать 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!

Такого квадратичного поведения можно полностью избежать: исходное решение (и любое количество других решений) не формирует эти промежуточные этапы копирования.

3
ответ дан 18 December 2019 в 14:44
поделиться

В документе для itertools есть функция flatten ()

2
ответ дан 18 December 2019 в 14:44
поделиться
  1. Вам следует избегать проверки типов в Python. В данном случае это означает отказ от произвольно вложенных структур, в которых вы различаете по типу. Вы можете создать свой собственный тип узла, который вы можете перемещать методами , отличными , кроме проверки типов, например, глядя на определенный атрибут.

  2. Для сведения одного уровня или ровно n уровней см. itertools.chain.from_iterable .

  3. Я не знаю, что вы подразумеваете под «функциональным». Этот код довольно функциональный: он использует рекурсию (не к его чести!) И не изменяет свой аргумент. (Строго говоря, он действительно использует изменяемое состояние для построения списка, но это именно то, как вы это делаете в Python.

  4. Я полагаю, что еще одним функциональным атрибутом будет ленивая оценка. Вы могли бы реализовать это таким образом

     def flatten ( toFlatten): 
    для элемента в toFlatten: 
    if isinstance (item, list): # Ewww, typchecking 
    для подэлемента в flatten (item): # они рассматривают возможность добавления {{ 1}} yield subitem # "yield from" на язык 
     #, чтобы задать синтаксис этого шаблона 
    else: 
    yield item 
     
  5. Рекурсия очень ограничена в Python (по крайней мере, во всех его основных реализациях), и его обычно следует избегать для произвольной глубины. Вполне возможно переписать это (и весь рекурсивный код), чтобы использовать итерацию, которая сделает его более масштабируемым (и менее функциональным, что это хорошая вещь в Python, которая не особенно подходит для FP.)

7
ответ дан 18 December 2019 в 14:44
поделиться
Другие вопросы по тегам:

Похожие вопросы: