725 votos

Hacer una lista plana de lista de listas en Python

Posibles Duplicados:
Aplanar un poco la lista en Python
La comprensión de acoplamiento de una secuencia de secuencias?

Me pregunto si hay un acceso directo para hacer una simple lista de lista de listas en Python.

Yo puedo hacer eso en un bucle for, pero tal vez hay algo de fresco "one-liner"? He probado con reducir, pero me da 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 (la más reciente call last): File "", line 1, en File "", line 1, en AttributeError: 'NoneType' objeto no tiene ningún atributo 'extender'

1182voto

Alex Martelli Puntos 330805

[item for sublist in l for item in sublist] es más rápido que los accesos directos publicado hasta el momento.

Para las pruebas, como siempre, puede utilizar la timeit módulo 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 accesos directos basados en + (incluyendo las implícitas uso en sum) son, por necesidad, O(L**2) cuando hay L sublistas -- como el resultado intermedio lista sigue creciendo, en cada paso, un nuevo resultado intermedio objeto de la lista obtiene asigna, y todos los elementos en el anterior resultado intermedio debe ser copiado (así como un par de nuevos añadidos al final). Así que (por simplicidad y sin pérdida de generalidad) dicen que tienen L sublistas yo los elementos de cada una: la primera vez que los elementos se copian de ida y vuelta L-1 veces, el segundo me elementos de L-2 veces, y así sucesivamente; número total de ejemplares, en tiempos de la suma de x de x de 1 a L excluido, es decir, I * (L**2)/2.

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

535voto

Shawn Chin Puntos 29756

Usted 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 de desembalaje de la lista:

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

Este enfoque es, sin duda, más fácil de leer que [item for sublist in l for item in sublist] y parece ser más rápido:

[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

276voto

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

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

46voto

jacob Puntos 605

@Nadia: Usted tiene que utilizar mucho más listas. A continuación, puede ver la diferencia bastante llamativo! Mis resultados para len(l) = 1600

A took 14.323 ms
B took 13.437 ms
C took 1.135 ms

donde:

A = reduce(lambda x,y: x+y,l)
B = sum(l, [])
C = [item for sublist in l for item in sublist]

32voto

Greg Hewgill Puntos 356191
>>> 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]

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

Una manera más rápida de hacer el reduce versión sería

>>> import operator
>>> l = [[1,2,3],[4,5,6], [7], [8,9]]
>>> reduce(operator.add, l)
[1, 2, 3, 4, 5, 6, 7, 8, 9]

Iteramos.com

Iteramos es una comunidad de desarrolladores que busca expandir el conocimiento de la programación mas allá del inglés.
Tenemos una gran cantidad de contenido, y también puedes hacer tus propias preguntas o resolver las de los demás.

Powered by: