Есть ли функциональный способ сделать это? - PullRequest
5 голосов
/ 18 марта 2010
def flattenList(toFlatten):
 final=[]
 for el in toFlatten:
  if isinstance(el, list):
   final.extend(flattenList(el))
  else:
   final.append(el)
 return final

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

Ответы [ 4 ]

7 голосов
/ 18 марта 2010
  1. Вы должны избегать проверки типов в Python. В этом случае это означает, что нужно избегать произвольно вложенных структур, в которых вы различаете тип. Вы можете создать свой собственный тип узла, который вы можете перемещать методами , отличными от , кроме проверки типов, например просмотром определенного атрибута.

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

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

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

    def flatten(toFlatten):
        for item in toFlatten:
            if isinstance(item, list): # Ewww, typchecking
                for subitem in flatten(item): # they are considering adding 
                    yield subitem             # "yield from" to the  language
                                              # to give this pattern syntax
            else:
                yield item
    
  5. Рекурсия очень ограничена в Python (по крайней мере, во всех его основных реализациях), и ее обычно следует избегать для произвольной глубины. Вполне возможно переписать этот (и весь рекурсивный код) для использования итерации, что сделает это более масштабируемым (и менее функциональным, что хорошо в Python, который не особенно подходит для FP.)

3 голосов
/ 18 марта 2010

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

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

2 голосов
/ 18 марта 2010

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

1 голос
/ 18 марта 2010

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

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

Он основан на чем-то похожем на схему.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...