functional-programming python list-comprehension

functional programming - comprensiones de la lista de pitones; ¿Comprimir una lista de listas?



python sum (13)

Google me trajo la siguiente solución:

def flatten(l): if isinstance(l,list): return sum(map(flatten,l)) else: return l

chicos. Intento encontrar la solución más elegante para un problema y me pregunto si Python tiene algo incorporado para lo que estoy tratando de hacer.

Lo que estoy haciendo es esto. Tengo una lista, A , y tengo una función f que toma un elemento y devuelve una lista. Puedo usar una lista de comprensión para convertir todo en A así;

[f(a) for a in A]

Pero esto devuelve una lista de listas;

[a1,a2,a3] => [[b11,b12],[b21,b22],[b31,b32]]

Lo que realmente quiero es obtener la lista aplanada;

[b11,b12,b21,b22,b31,b32]

Ahora, otros lenguajes lo tienen; tradicionalmente se denomina flatmap en los lenguajes de programación funcionales, y .Net lo llama SelectMany . ¿Python tiene algo similar? ¿Hay una forma ordenada de asignar una función sobre una lista y aplanar el resultado?

El problema real que estoy tratando de resolver es esto; comenzando con una lista de directorios, encuentre todos los subdirectorios. asi que;

import os dirs = ["c://usr", "c://temp"] subs = [os.listdir(d) for d in dirs] print subs

currentliy me da una lista de listas, pero realmente quiero una lista.


La pregunta propuesta flatmap . Se proponen algunas implementaciones pero pueden crear listas intermedias innecesarias. Aquí hay una implementación basada en iteradores.

def flatmap(func, *iterable): return itertools.chain.from_iterable(map(func, *iterable)) In [148]: list(flatmap(os.listdir, [''c:/mfg'',''c:/Intel''])) Out[148]: [''SPEC.pdf'', ''W7ADD64EN006.cdr'', ''W7ADD64EN006.pdf'', ''ExtremeGraphics'', ''Logs'']

En Python 2.x, use itertools.map en lugar del map .


Puede concatenar listas usando el operador de suma normal:

>>> [1, 2] + [3, 4] [1, 2, 3, 4]

La sum función incorporada agregará los números en una secuencia y opcionalmente puede comenzar desde un valor específico:

>>> sum(xrange(10), 100) 145

Combine lo anterior para aplanar una lista de listas:

>>> sum([[1, 2], [3, 4]], []) [1, 2, 3, 4]

Ahora puedes definir tu flatmap :

>>> def flatmap(f, seq): ... return sum([f(s) for s in seq], []) ... >>> flatmap(range, [1,2,3]) [0, 0, 1, 0, 1, 2]

Editar: Acabo de ver la crítica en los comentarios en busca de otra respuesta y creo que es correcto que Python compilará innecesariamente y que la basura recolecte muchas listas más pequeñas con esta solución. Entonces, lo mejor que se puede decir al respecto es que es muy simple y conciso si estás acostumbrado a la programación funcional :-)


Puede encontrar una buena respuesta en las recetas de itertools:

def flatten(listOfLists): return list(chain.from_iterable(listOfLists))

(Nota: requiere Python 2.6+)


Puede tener iteraciones anidadas en una sola lista de comprensión:

[filename for path in dirs for filename in os.listdir(path)]


Puedes probar itertools.chain() , así:

import itertools import os dirs = ["c://usr", "c://temp"] subs = list(itertools.chain(*[os.listdir(d) for d in dirs])) print subs

itertools.chain() devuelve un iterador, de ahí el pasar a list() .


Puedes usar pyxtension :

from pyxtension.streams import stream stream([ [1,2,3], [4,5], [], [6] ]).flatMap() == range(7)


Usted podría simplemente hacer lo siguiente:

subs = [] for d in dirs: subs.extend(os.listdir(d))


>>> listOfLists = [[1, 2],[3, 4, 5], [6]] >>> reduce(list.__add__, listOfLists) [1, 2, 3, 4, 5, 6]

Supongo que la solución itertools es más eficiente que esto, pero se siente muy pitónico y evita tener que importar una biblioteca solo por el simple hecho de una operación de lista.


If listA=[list1,list2,list3] flattened_list=reduce(lambda x,y:x+y,listA)

Esto lo hara.


def flat_list(arr): send_back = [] for i in arr: if type(i) == list: send_back += flat_list(i) else: send_back.append(i) return send_back


import itertools x=[[''b11'',''b12''],[''b21'',''b22''],[''b31'']] y=list(itertools.chain(*x)) print y

itertools funcionará desde python2.3 y superior


subs = [] map(subs.extend, (os.listdir(d) for d in dirs))

(pero la respuesta de las hormigas es mejor, +1 para él)