Aplanar una lista de listas irregulares (anidadas arbitrariamente)
Sí, sé que este tema se ha tratado antes:
- ¿Idioma de Python para encadenar (aplanar) un iterable infinito de iterables finitos?
- Aplanar una lista poco profunda en Python
- ¿Comprensión para aplanar una secuencia de secuencias?
- ¿Cómo hago una lista plana a partir de una lista de listas?
pero hasta donde yo sé, todas las soluciones, excepto una, fallan en una lista como [[[1, 2, 3], [4, 5]], 6]
, donde está el resultado deseado [1, 2, 3, 4, 5, 6]
(o quizás incluso mejor, un iterador).
La única solución que vi que funciona para un anidamiento arbitrario se encuentra en esta pregunta :
def flatten(x):
result = []
for el in x:
if hasattr(el, "__iter__") and not isinstance(el, basestring):
result.extend(flatten(el))
else:
result.append(el)
return result
¿Es este el mejor enfoque? ¿Pasé por alto algo? ¿Algún problema?
El uso de funciones de generador puede hacer que su ejemplo sea más fácil de leer y mejorar el rendimiento.
Pitón 2
Usando el Iterable
ABC agregado en 2.6:
from collections import Iterable
def flatten(xs):
for x in xs:
if isinstance(x, Iterable) and not isinstance(x, basestring):
for item in flatten(x):
yield item
else:
yield x
Pitón 3
En Python 3, basestring
ya no existe, pero la tupla (str, bytes)
da el mismo efecto. Además, el yield from
operador devuelve un artículo de un generador uno por uno.
from collections.abc import Iterable
def flatten(xs):
for x in xs:
if isinstance(x, Iterable) and not isinstance(x, (str, bytes)):
yield from flatten(x)
else:
yield x
Mi solución:
import collections
def flatten(x):
if isinstance(x, collections.Iterable):
return [a for i in x for a in flatten(i)]
else:
return [x]
Un poco más conciso, pero más o menos igual.