Usando recursión con mapa en python

Estoy tratando de aprender conceptos de progtwigción funcional. Un ejercicio, aplanar una lista anidada usando map / reduce. Mi código.

lists = [ 1 , 2 , [ 3 , 4, 5], 6, [7, 8, 9] ] def flatten(lists): return map(lambda x: flatten(x) if isinstance(x,list) else x, lists) print flatten(lists) 

Me sale de salida igual que la entrada. Qué hice mal ? ¿Cómo funciona la recursión con map ()?

Aquí hay una solución que usa tanto map como reduce :

 def flatten(seq): return reduce(operator.add, map( lambda x: flatten(x) if isinstance(x,list) else [x], seq)) 

Como dijo Martijn, el mapa produce la misma cantidad de elementos que recibe en su entrada, por lo que el paso exterior debe ser la reduce llamadas que produce una sola salida para todas las entradas. map se puede usar aquí para hacer que todas las entradas sean consistentes: es decir, una secuencia de listas.

No puedes resolver este problema con map() . Las llamadas recursivas devuelven una lista, por lo que para una lista en la entrada reemplazó el resultado con otra lista . map() siempre tiene que producir el mismo número de elementos en la salida que se dio en la entrada, después de todo.

Con reduce() puede agregar más elementos a una lista existente:

 def flatten(lists): return reduce(lambda res, x: res + (flatten(x) if isinstance(x, list) else [x]), lists, []) 

Esto comienza con una lista vacía, y agrega elementos a eso para cada elemento en las lists . Si ese elemento es una lista en sí misma, se utiliza la recursión.

Esto produce el resultado esperado:

 >>> def flatten(lists): ... return reduce(lambda res, x: res + (flatten(x) if isinstance(x, list) else [x]), lists, []) ... >>> lists = [ 1 , 2 , [ 3 , 4, 5], 6, [7, 8, 9] ] >>> flatten(lists) [1, 2, 3, 4, 5, 6, 7, 8, 9] 

Ya que está usando el map en su función, devuelve una lista incluso cuando llama a la función en forma recursiva.

Por lo tanto, en lugar de usar map o reduce que no son formas de Pythonic para aplanar una lista anidada, puede usar una función de generador:

 >>> def flatten(lists): ... for sub in lists: ... if isinstance(sub,list): ... for i in sub: ... yield i ... else: ... yield sub ... >>> >>> list(flatten(lists)) [1, 2, 3, 4, 5, 6, 7, 8, 9] 

Si aún desea demandar la función de map , puede utilizar el siguiente enfoque:

 >>> def flatten(lists,total=[]): ... map(lambda x: total.extend(x) if isinstance(x,list) else total.append(x), lists) ... return total ... >>> flatten(lists) [1, 2, 3, 4, 5, 6, 7, 8, 9] 

Solución alternativa con solo recursión:

 lists = [ 1 , 2 , [ 3 , 4, 5], 6, [7, 8, 9] ] def flatten(lists): return (flatten(lists[0]) + flatten(lists[1:]) if isinstance(lists[0],list) else [lists[0]]+flatten(lists[1:])) if len(lists)>0 else []