Hacer una lista plana de lista de listas en Python


Me pregunto si hay un atajo para hacer una lista simple de la lista de listas en Python.

Puedo hacer eso en un bucle for, pero tal vez hay algún "one-liner"genial? Lo intenté con reduce , pero me sale un error.

Código

l = [[1, 2, 3], [4, 5, 6], [7], [8, 9]]
reduce(lambda x, y: x.extend(y), l)

Mensaje de error

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 1, in <lambda>
AttributeError: 'NoneType' object has no attribute 'extend'
Author: dreftymac, 2009-06-05

30 answers

flat_list = [item for sublist in l for item in sublist]

Que significa:

for sublist in l:
    for item in sublist:
        flat_list.append(item)

Es más rápido que los atajos publicados hasta ahora. (l es la lista a aplanar.)

Aquí está la función correspondiente:

flatten = lambda l: [item for sublist in l for item in sublist]

Para evidencia, como siempre, puede usar el módulo timeit en la biblioteca estándar:

$ python -mtimeit -s'l=[[1,2,3],[4,5,6], [7], [8,9]]*99' '[item for sublist in l for item in sublist]'
10000 loops, best of 3: 143 usec per loop
$ python -mtimeit -s'l=[[1,2,3],[4,5,6], [7], [8,9]]*99' 'sum(l, [])'
1000 loops, best of 3: 969 usec per loop
$ python -mtimeit -s'l=[[1,2,3],[4,5,6], [7], [8,9]]*99' 'reduce(lambda x,y: x+y,l)'
1000 loops, best of 3: 1.1 msec per loop

Explicación: los atajos basados en + (incluyendo el uso implícito en sum) son, por necesidad, O(L**2) cuando hay sublistas L as como la lista de resultados intermedios sigue haciéndose más larga, en cada paso a se asigna un nuevo objeto de lista de resultados intermedios, y se deben copiar todos los elementos del resultado intermedio anterior (así como algunos nuevos agregados al final). Por lo tanto (para simplificar y sin pérdida real de generalidad) digamos que tiene sublistas L de elementos I cada uno: los primeros elementos I se copian de ida y vuelta L-1 veces, los segundos elementos I L-2 veces, y así sucesivamente; el número total de copias es I veces la suma de x para x de 1 a L excluido, es decir, I * (L**2)/2.

La lista de comprensión solo genera una lista, una vez, y copia cada elemento (desde su lugar de residencia original a la lista de resultados) también exactamente una vez.

 3158
Author: Alex Martelli,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-06-14 21:53:08

Puede utilizar itertools.chain():

>>> import itertools
>>> list2d = [[1,2,3],[4,5,6], [7], [8,9]]
>>> merged = list(itertools.chain(*list2d))

O, en Python >=2.6, use itertools.chain.from_iterable() que no requiere desempaquetar la lista:

>>> import itertools
>>> list2d = [[1,2,3],[4,5,6], [7], [8,9]]
>>> merged = list(itertools.chain.from_iterable(list2d))

Este enfoque es posiblemente más legible que [item for sublist in l for item in sublist] y parece ser más rápido también:

[me@home]$ python -mtimeit -s'l=[[1,2,3],[4,5,6], [7], [8,9]]*99;import itertools' 'list(itertools.chain.from_iterable(l))'
10000 loops, best of 3: 24.2 usec per loop
[me@home]$ python -mtimeit -s'l=[[1,2,3],[4,5,6], [7], [8,9]]*99' '[item for sublist in l for item in sublist]'
10000 loops, best of 3: 45.2 usec per loop
[me@home]$ python -mtimeit -s'l=[[1,2,3],[4,5,6], [7], [8,9]]*99' 'sum(l, [])'
1000 loops, best of 3: 488 usec per loop
[me@home]$ python -mtimeit -s'l=[[1,2,3],[4,5,6], [7], [8,9]]*99' 'reduce(lambda x,y: x+y,l)'
1000 loops, best of 3: 522 usec per loop
[me@home]$ python --version
Python 2.7.3
 1129
Author: Shawn Chin,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-03-12 17:15:50

Nota del autor: Esto es ineficiente. Pero divertido, porque las mónadas son increíbles. No es apropiado para el código Python de producción.

>>> sum(l, [])
[1, 2, 3, 4, 5, 6, 7, 8, 9]

Esto solo suma los elementos iterables pasados en el primer argumento, tratando el segundo argumento como el valor inicial de la suma (si no se da, 0 se usa en su lugar y este caso le dará un error).

Debido a que está sumando listas anidadas, en realidad obtiene [1,3]+[2,4] como resultado de sum([[1,3],[2,4]],[]), que es igual a [1,3,2,4].

Tenga en cuenta que solo funciona en listas de listas. Para las listas de listas de listas, necesitarás otra solución.

 656
Author: Triptych,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-01-09 16:25:42

Probé la mayoría de las soluciones sugeridas con perfplot (un proyecto favorito mío, esencialmente un envoltorio alrededor de timeit), y encontré

list(itertools.chain.from_iterable(a))

Ser la solución más rápida (si se concatenan más de 10 listas).

introduzca la descripción de la imagen aquí


Código para reproducir la trama:

import functools
import itertools
import numpy
import operator
import perfplot


def forfor(a):
    return [item for sublist in a for item in sublist]


def sum_brackets(a):
    return sum(a, [])


def functools_reduce(a):
    return functools.reduce(operator.concat, a)


def itertools_chain(a):
    return list(itertools.chain.from_iterable(a))


def numpy_flat(a):
    return list(numpy.array(a).flat)


def numpy_concatenate(a):
    return list(numpy.concatenate(a))


perfplot.show(
    setup=lambda n: [list(range(10))] * n,
    kernels=[
        forfor, sum_brackets, functools_reduce, itertools_chain, numpy_flat,
        numpy_concatenate
        ],
    n_range=[2**k for k in range(16)],
    logx=True,
    logy=True,
    xlabel='num lists'
    )
 164
Author: Nico Schlömer,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-06-18 11:05:28
from functools import reduce #python 3

>>> l = [[1,2,3],[4,5,6], [7], [8,9]]
>>> reduce(lambda x,y: x+y,l)
[1, 2, 3, 4, 5, 6, 7, 8, 9]

El método extend() en su ejemplo modifica x en lugar de devolver un valor útil (que reduce() espera).

Una forma más rápida de hacer la versión reduce sería

>>> import operator
>>> l = [[1,2,3],[4,5,6], [7], [8,9]]
>>> reduce(operator.concat, l)
[1, 2, 3, 4, 5, 6, 7, 8, 9]
 109
Author: Greg Hewgill,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-01-02 05:02:41

Aquí hay un enfoque general que se aplica a números, cadenas, listas anidadas y contenedores mixtos.

Código

from collections import Iterable


def flatten(items):
    """Yield items from any nested iterable; see Reference."""
    for x in items:
        if isinstance(x, Iterable) and not isinstance(x, (str, bytes)):
            for sub_x in flatten(x):
                yield sub_x
        else:
            yield x

Nota: en Python 3, yield from flatten(x) puede reemplazar for sub_x in flatten(x): yield sub_x

Demo

lst = [[1, 2, 3], [4, 5, 6], [7], [8, 9]]
list(flatten(lst))                                         # nested lists
# [1, 2, 3, 4, 5, 6, 7, 8, 9]

mixed = [[1, [2]], (3, 4, {5, 6}, 7), 8, "9"]              # numbers, strs, nested & mixed
list(flatten(mixed))
# [1, 2, 3, 4, 5, 6, 7, 8, '9']

Referencia

  • Esta solución se modifica de una receta en Beazley, D. y B. Jones. Receta 4.14, Python Cookbook 3rd Ed., O'Reilly Media Inc. Sebastopol, CA: 2013.
  • Encontrado un anterior SO post, posiblemente la demostración original.
 62
Author: pylang,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-07-26 17:00:44

Retiro mi declaración. sum no es el ganador. Aunque es más rápido cuando la lista es pequeña. Pero el rendimiento se degrada significativamente con listas más grandes.

>>> timeit.Timer(
        '[item for sublist in l for item in sublist]',
        'l=[[1, 2, 3], [4, 5, 6, 7, 8], [1, 2, 3, 4, 5, 6, 7]] * 10000'
    ).timeit(100)
2.0440959930419922

La versión sum todavía se está ejecutando durante más de un minuto y aún no se ha procesado.

Para listas de medios:

>>> timeit.Timer(
        '[item for sublist in l for item in sublist]',
        'l=[[1, 2, 3], [4, 5, 6, 7, 8], [1, 2, 3, 4, 5, 6, 7]] * 10'
    ).timeit()
20.126545906066895
>>> timeit.Timer(
        'reduce(lambda x,y: x+y,l)',
        'l=[[1, 2, 3], [4, 5, 6, 7, 8], [1, 2, 3, 4, 5, 6, 7]] * 10'
    ).timeit()
22.242258071899414
>>> timeit.Timer(
        'sum(l, [])',
        'l=[[1, 2, 3], [4, 5, 6, 7, 8], [1, 2, 3, 4, 5, 6, 7]] * 10'
    ).timeit()
16.449732065200806

Usando listas pequeñas y timeit: number = 1000000

>>> timeit.Timer(
        '[item for sublist in l for item in sublist]',
        'l=[[1, 2, 3], [4, 5, 6, 7, 8], [1, 2, 3, 4, 5, 6, 7]]'
    ).timeit()
2.4598159790039062
>>> timeit.Timer(
        'reduce(lambda x,y: x+y,l)',
        'l=[[1, 2, 3], [4, 5, 6, 7, 8], [1, 2, 3, 4, 5, 6, 7]]'
    ).timeit()
1.5289170742034912
>>> timeit.Timer(
        'sum(l, [])',
        'l=[[1, 2, 3], [4, 5, 6, 7, 8], [1, 2, 3, 4, 5, 6, 7]]'
    ).timeit()
1.0598428249359131
 32
Author: Nadia Alramli,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-12-23 09:14:58

¿Por qué usas extend?

reduce(lambda x, y: x+y, l)

Esto debería funcionar bien.

 27
Author: Andrea Ambu,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-12-31 12:07:09

Parece haber una confusión con operator.add! Cuando se agregan dos listas juntas, el término correcto para eso es concat, no agregar. operator.concat es lo que necesitas usar.

Si estás pensando funcional, es tan fácil como esto::

>>> list2d = ((1, 2, 3), (4, 5, 6), (7,), (8, 9))
>>> reduce(operator.concat, list2d)
(1, 2, 3, 4, 5, 6, 7, 8, 9)

Verá que reduce respeta el tipo de secuencia, por lo que cuando suministra una tupla, obtiene una tupla. probemos con una lista::

>>> list2d = [[1, 2, 3],[4, 5, 6], [7], [8, 9]]
>>> reduce(operator.concat, list2d)
[1, 2, 3, 4, 5, 6, 7, 8, 9]

Aha, usted consigue detrás una lista.

¿Qué tal el rendimiento::

>>> list2d = [[1, 2, 3],[4, 5, 6], [7], [8, 9]]
>>> %timeit list(itertools.chain.from_iterable(list2d))
1000000 loops, best of 3: 1.36 µs per loop

From_iterable es bastante rápido! Pero no es comparación para reducir con concat.

>>> list2d = ((1, 2, 3),(4, 5, 6), (7,), (8, 9))
>>> %timeit reduce(operator.concat, list2d)
1000000 loops, best of 3: 492 ns per loop
 21
Author: Meitham,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-09-30 21:28:25

Si desea aplanar una estructura de datos donde no sabe qué tan profunda está anidada, podría usar iteration_utilities.deepflatten1

>>> from iteration_utilities import deepflatten

>>> l = [[1, 2, 3], [4, 5, 6], [7], [8, 9]]
>>> list(deepflatten(l, depth=1))
[1, 2, 3, 4, 5, 6, 7, 8, 9]

>>> l = [[1, 2, 3], [4, [5, 6]], 7, [8, 9]]
>>> list(deepflatten(l))
[1, 2, 3, 4, 5, 6, 7, 8, 9]

Es un generador por lo que necesita convertir el resultado a un list o iterar explícitamente sobre él.


Para aplanar solo un nivel y si cada uno de los elementos es iterable, también puede usar iteration_utilities.flatten que en sí es sólo una envoltura delgada alrededor itertools.chain.from_iterable:

>>> from iteration_utilities import flatten
>>> l = [[1, 2, 3], [4, 5, 6], [7], [8, 9]]
>>> list(flatten(l))
[1, 2, 3, 4, 5, 6, 7, 8, 9]

Solo para agregar algunos tiempos (basado en Nico Schlömer respuesta que no incluía la función presentada en esta respuesta):

introduzca la descripción de la imagen aquí

Es una gráfica log-log para acomodar el enorme rango de valores abarcados. Para el razonamiento cualitativo: Más bajo es mejor.

Los resultados muestran que si el iterable contiene solo unos pocos iterables internos, entonces sum será el más rápido, sin embargo, para iterables largos solo el itertools.chain.from_iterable, iteration_utilities.deepflatten o la comprensión anidada tiene un rendimiento razonable con itertools.chain.from_iterable siendo el más rápido (como ya noted by Nico Schlömer).

from itertools import chain
from functools import reduce
from collections import Iterable  # or from collections.abc import Iterable
import operator
from iteration_utilities import deepflatten

def nested_list_comprehension(lsts):
    return [item for sublist in lsts for item in sublist]

def itertools_chain_from_iterable(lsts):
    return list(chain.from_iterable(lsts))

def pythons_sum(lsts):
    return sum(lsts, [])

def reduce_add(lsts):
    return reduce(lambda x, y: x + y, lsts)

def pylangs_flatten(lsts):
    return list(flatten(lsts))

def flatten(items):
    """Yield items from any nested iterable; see REF."""
    for x in items:
        if isinstance(x, Iterable) and not isinstance(x, (str, bytes)):
            yield from flatten(x)
        else:
            yield x

def reduce_concat(lsts):
    return reduce(operator.concat, lsts)

def iteration_utilities_deepflatten(lsts):
    return list(deepflatten(lsts, depth=1))


from simple_benchmark import benchmark

b = benchmark(
    [nested_list_comprehension, itertools_chain_from_iterable, pythons_sum, reduce_add,
     pylangs_flatten, reduce_concat, iteration_utilities_deepflatten],
    arguments={2**i: [[0]*5]*(2**i) for i in range(1, 13)},
    argument_name='number of inner lists'
)

b.plot()

1 Descargo de responsabilidad: Soy el autor de esa biblioteca

 20
Author: MSeifert,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-04-18 21:27:43

Considere instalar el more_itertools paquete.

> pip install more_itertools

Se envía con una implementación para flatten (fuente , de las recetas de itertools ):

import more_itertools


lst = [[1, 2, 3], [4, 5, 6], [7], [8, 9]]
list(more_itertools.flatten(lst))
# [1, 2, 3, 4, 5, 6, 7, 8, 9]

A partir de la versión 2.4, puede aplanar iterables más complicados y anidados con more_itertools.collapse (source , contributed by abarnet).

lst = [[1, 2, 3], [4, 5, 6], [7], [8, 9]]
list(more_itertools.collapse(lst)) 
# [1, 2, 3, 4, 5, 6, 7, 8, 9]

lst = [[1, 2, 3], [[4, 5, 6]], [[[7]]], 8, 9]              # complex nesting
list(more_itertools.collapse(lst))
# [1, 2, 3, 4, 5, 6, 7, 8, 9]
 15
Author: pylang,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-07-13 21:06:00

La razón por la que su función no funcionó: extend extiende el array in-place y no lo devuelve. Todavía puedes devolver x desde lambda, usando algún truco:

reduce(lambda x,y: x.extend(y) or x, l)

Nota: extender es más eficiente que + en listas.

 13
Author: Igor Krivokon,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-06-04 20:47:13

Una mala característica de la función anterior de Anil es que requiere que el usuario especifique siempre manualmente que el segundo argumento sea una lista vacía []. Esto debería ser un valor predeterminado. Debido a la forma en que funcionan los objetos Python, estos deben establecerse dentro de la función, no en los argumentos.

Aquí está una función de trabajo:

def list_flatten(l, a=None):
    #check a
    if a is None:
        #initialize with empty list
        a = []

    for i in l:
        if isinstance(i, list):
            list_flatten(i, a)
        else:
            a.append(i)
    return a

Pruebas:

In [2]: lst = [1, 2, [3], [[4]],[5,[6]]]

In [3]: lst
Out[3]: [1, 2, [3], [[4]], [5, [6]]]

In [11]: list_flatten(lst)
Out[11]: [1, 2, 3, 4, 5, 6]
 8
Author: Deleet,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-11-29 03:45:43
def flatten(l, a):
    for i in l:
        if isinstance(i, list):
            flatten(i, a)
        else:
            a.append(i)
    return a

print(flatten([[[1, [1,1, [3, [4,5,]]]], 2, 3], [4, 5],6], []))

# [1, 1, 1, 3, 4, 5, 2, 3, 4, 5, 6]
 7
Author: Anil,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-11-28 08:48:33

Los siguientes me parecen más simples:

>>> import numpy as np
>>> l = [[1, 2, 3], [4, 5, 6], [7], [8, 9]]
>>> print (np.concatenate(l))
[1 2 3 4 5 6 7 8 9]
 7
Author: devil in the detail,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-07-05 05:14:38

También se puede usar Numpy's flat :

import numpy as np
list(np.array(l).flat)

Editar 02/11/2016: Solo funciona cuando las sublistas tienen dimensiones idénticas.

 6
Author: mdh,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-11-02 09:59:40

matplotlib.cbook.flatten() funcionará para listas anidadas incluso si anidan más profundamente que el ejemplo.

import matplotlib
l = [[1, 2, 3], [4, 5, 6], [7], [8, 9]]
print(list(matplotlib.cbook.flatten(l)))
l2 = [[1, 2, 3], [4, 5, 6], [7], [8, [9, 10, [11, 12, [13]]]]]
print list(matplotlib.cbook.flatten(l2))

Resultado:

[1, 2, 3, 4, 5, 6, 7, 8, 9]
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13]

Esto es 18 veces más rápido que el subrayado._.aplanar:

Average time over 1000 trials of matplotlib.cbook.flatten: 2.55e-05 sec
Average time over 1000 trials of underscore._.flatten: 4.63e-04 sec
(time for underscore._)/(time for matplotlib.cbook) = 18.1233394636
 6
Author: EL_DON,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-07-20 18:16:43

Código simple para underscore.py ventilador del paquete

from underscore import _
_.flatten([[1, 2, 3], [4, 5, 6], [7], [8, 9]])
# [1, 2, 3, 4, 5, 6, 7, 8, 9]

Resuelve todos los problemas de aplanamiento (ninguno elemento de lista o anidamiento complejo)

from underscore import _
# 1 is none list item
# [2, [3]] is complex nesting
_.flatten([1, [2, [3]], [4, 5, 6], [7], [8, 9]])
# [1, 2, 3, 4, 5, 6, 7, 8, 9]

Puede instalar underscore.py con pip

pip install underscore.py
 5
Author: Vu Anh,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-03-25 05:09:57
def flatten(alist):
    if alist == []:
        return []
    elif type(alist) is not list:
        return [alist]
    else:
        return flatten(alist[0]) + flatten(alist[1:])
 4
Author: englealuze,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-08-08 14:59:07

Puede usar numpy :
flat_list = list(np.concatenate(list_of_list))

 4
Author: A. Attia,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-07-24 09:11:26

Si estás dispuesto a renunciar a una pequeña cantidad de velocidad para un aspecto más limpio, entonces puedes usar numpy.concatenate().tolist() o numpy.concatenate().ravel().tolist():

import numpy

l = [[1, 2, 3], [4, 5, 6], [7], [8, 9]] * 99

%timeit numpy.concatenate(l).ravel().tolist()
1000 loops, best of 3: 313 µs per loop

%timeit numpy.concatenate(l).tolist()
1000 loops, best of 3: 312 µs per loop

%timeit [item for sublist in l for item in sublist]
1000 loops, best of 3: 31.5 µs per loop

Puedes encontrar más información aquí en los documentos numpy.concatenar y numpy.ravel

 3
Author: mkultra,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-10-27 03:31:54
flat_list = []
for i in list_of_list:
    flat_list+=i

Este Código también funciona bien, ya que solo extiende la lista hasta el final. Aunque es muy similar pero solo tiene un bucle for. Por lo tanto, tiene menos complejidad que la adición de 2 bucles for.

 3
Author: Deepak Yadav,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-06-20 11:12:25

La solución más rápida que he encontrado (para lista grande de todos modos):

import numpy as np
#turn list into an array and flatten()
np.array(l).flatten()

Hecho! Por supuesto, puede volver a convertirlo en una lista ejecutando list (l)

 2
Author: Canuck,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-11-28 21:09:09

Recientemente me encontré con una situación en la que tenía una mezcla de cadenas y datos numéricos en sublistas como

test = ['591212948',
['special', 'assoc', 'of', 'Chicago', 'Jon', 'Doe'],
['Jon'],
['Doe'],
['fl'],
92001,
555555555,
'hello',
['hello2', 'a'],
'b',
['hello33', ['z', 'w'], 'b']]

Donde métodos como flat_list = [item for sublist in test for item in sublist] no han funcionado. Por lo tanto, se me ocurrió la siguiente solución para 1+ nivel de sublistas

def concatList(data):
    results = []
    for rec in data:
        if type(rec) == list:
            results += rec
            results = concatList(results)
        else:
            results.append(rec)
    return results

Y el resultado

In [38]: concatList(test)
Out[38]:
 Out[60]:
['591212948',
'special',
'assoc',
'of',
'Chicago',
'Jon',
'Doe',
'Jon',
'Doe',
'fl',
92001,
555555555,
'hello',
'hello2',
'a',
'b',
'hello33',
'z',
'w',
'b']
 2
Author: Jon,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-09-21 19:54:13

Otro enfoque inusual que funciona para listas hetero y homogéneas de enteros:

from typing import List


def flatten(l: list) -> List[int]:
    """Flatten an arbitrary deep nested list of lists of integers.

    Examples:
        >>> flatten([1, 2, [1, [10]]])
        [1, 2, 1, 10]

    Args:
        l: Union[l, Union[int, List[int]]

    Returns:
        Flatted list of integer
    """
    return [int(i.strip('[ ]')) for i in str(l).split(',')]
 2
Author: tharndt,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-09-13 11:34:20

La respuesta aceptada no funcionó para mí cuando se trata de listas basadas en texto de longitudes variables. Aquí hay un enfoque alternativo que funcionó para mí.

l = ['aaa', 'bb', 'cccccc', ['xx', 'yyyyyyy']]

Respuesta aceptada que hizo no trabajo:

flat_list = [item for sublist in l for item in sublist]
print(flat_list)
['a', 'a', 'a', 'b', 'b', 'c', 'c', 'c', 'c', 'c', 'c', 'xx', 'yyyyyyy']

Nueva solución propuesta que hizo trabajo para mí:

flat_list = []
_ = [flat_list.extend(item) if isinstance(item, list) else flat_list.append(item) for item in l if item]
print(flat_list)
['aaa', 'bb', 'cccccc', 'xx', 'yyyyyyy']
 2
Author: user9074332,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-10-12 01:32:31

Puede evitar llamadas recursivas a la pila usando una estructura de datos de pila real de manera bastante simple.

alist = [1,[1,2],[1,2,[4,5,6],3, "33"]]
newlist = []

while len(alist) > 0 :
  templist = alist.pop()
  if type(templist) == type(list()) :
    while len(templist) > 0 :
      temp = templist.pop()
      if type(temp) == type(list()) :
        for x in temp :
          templist.append(x)
      else :
        newlist.append(temp)
  else :
    newlist.append(templist)
print(list(reversed(newlist)))
 1
Author: FredMan,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-10-19 05:46:09

Esta puede no ser la forma más eficiente, pero pensé en poner un solo forro (en realidad un dos líneas). Ambas versiones funcionarán en listas anidadas de jerarquías arbitrarias, y explotarán las características del lenguaje (Python3.5) y la recursión.

def make_list_flat (l):
    flist = []
    flist.extend ([l]) if (type (l) is not list) else [flist.extend (make_list_flat (e)) for e in l]
    return flist

a = [[1, 2], [[[[3, 4, 5], 6]]], 7, [8, [9, [10, 11], 12, [13, 14, [15, [[16, 17], 18]]]]]]
flist = make_list_flat(a)
print (flist)

La salida es

[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18]

Esto funciona de una primera manera profunda. La recursión baja hasta que encuentra un elemento que no es de lista, luego extiende la variable local flist y luego la devuelve al padre. Cada vez que se devuelve flist, se extiende a la los padres flist en la lista de comprensión. Por lo tanto, en la raíz, se devuelve una lista plana.

El anterior crea varias listas locales y las devuelve que se utilizan para extender la lista del padre. Creo que el camino alrededor de esto puede ser la creación de un gloabl flist, como a continuación.

a = [[1, 2], [[[[3, 4, 5], 6]]], 7, [8, [9, [10, 11], 12, [13, 14, [15, [[16, 17], 18]]]]]]
flist = []
def make_list_flat (l):
    flist.extend ([l]) if (type (l) is not list) else [make_list_flat (e) for e in l]

make_list_flat(a)
print (flist)

La salida es de nuevo

[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18]

Aunque no estoy seguro en este momento sobre la eficiencia.

 1
Author: phoxis,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-05-20 08:47:32

Nota: a Continuación se aplica a Python 3.3+ porque utiliza yield_from. six también es un paquete de terceros, aunque es estable. Alternativamente, puedes usar sys.version.


En el caso de obj = [[1, 2,], [3, 4], [5, 6]], todas las soluciones aquí son buenas, incluyendo la comprensión de la lista y itertools.chain.from_iterable.

Sin embargo, considere este caso un poco más complejo:

>>> obj = [[1, 2, 3], [4, 5], 6, 'abc', [7], [8, [9, 10]]]

Hay varios problemas aquí:

  • Un elemento, 6, es solo un escalar; no es iterable, por lo que las rutas anteriores fallarán aquí.
  • Un elemento, 'abc', es técnicamente iterable (todos los str son). Sin embargo, leyendo entre líneas un poco, no quieres tratarlo como tal want quieres tratarlo como un solo elemento.
  • El elemento final, [8, [9, 10]] es en sí mismo un iterable anidado. Comprensión básica de la lista y chain.from_iterable solo extraer "1 nivel abajo."

Puede remediar esto de la siguiente manera:

>>> from collections import Iterable
>>> from six import string_types

>>> def flatten(obj):
...     for i in obj:
...         if isinstance(i, Iterable) and not isinstance(i, string_types):
...             yield from flatten(i)
...         else:
...             yield i


>>> list(flatten(obj))
[1, 2, 3, 4, 5, 6, 'abc', 7, 8, 9, 10]

Aquí, comprueba que el subelemento (1) es iterable con Iterable, un ABC de itertools, pero también quiere asegurarse de que (2) el elemento es no "similar a una cadena."

 1
Author: Brad Solomon,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-06-19 19:38:25

Limpiado @Deleet ejemplo

from collections import Iterable

def flatten(l, a=[]):
    for i in l:
        if isinstance(i, Iterable):
            flatten(i, a)
        else:
            a.append(i)
    return a

daList = [[1,4],[5,6],[23,22,234,2],[2], [ [[1,2],[1,2]],[[11,2],[11,22]] ] ]

print(flatten(daList))

Ejemplo: https://repl.it/G8mb/0

 0
Author: Kevin Postal,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-03-22 17:01:57