¿Comprensión de la lista en una lista anidada?


219

Tengo esta lista anidada:

l = [['40', '20', '10', '30'], ['20', '20', '20', '20', '20', '30', '20'], ['30', '20', '30', '50', '10', '30', '20', '20', '20'], ['100', '100'], ['100', '100', '100', '100', '100'], ['100', '100', '100', '100']]

Ahora, lo que quiero hacer es convertir cada elemento en una lista para flotar. Mi solución es esta:

newList = []
for x in l:
  for y in x:
    newList.append(float(y))

Pero, ¿se puede hacer esto usando una comprensión de lista anidada, verdad?

lo que he hecho es:

[float(y) for y in x for x in l]

Pero el resultado es un montón de 100 con la suma de 2400.

Cualquier solución, una explicación sería muy apreciada. ¡Gracias!


15
¿ También quieres aplanar tu lista?
Greg Hewgill

@GregHewgill: OP no respondió, pero según la respuesta que aceptaron, parece que querían mantener el anidamiento tal como está.
smci

Respuestas:


317

Así es como lo haría con una comprensión de lista anidada:

[[float(y) for y in x] for x in l]

Esto le daría una lista de listas, similar a la que comenzó, excepto con flotantes en lugar de cadenas. Si quieres una lista plana, entonces la usarías [float(y) for x in l for y in x].


190

A continuación, le mostramos cómo convertir el bucle anidado para la comprensión de la lista anidada:

ingrese la descripción de la imagen aquí

Así es como funciona la comprensión de la lista anidada:

            l a b c d e f
                  
In [1]: l = [ [ [ [ [ [ 1 ] ] ] ] ] ]
In [2]: for a in l:
   ...:     for b in a:
   ...:         for c in b:
   ...:             for d in c:
   ...:                 for e in d:
   ...:                     for f in e:
   ...:                         print(float(f))
   ...:                         
1.0

In [3]: [float(f)
         for a in l
   ...:     for b in a
   ...:         for c in b
   ...:             for d in c
   ...:                 for e in d
   ...:                     for f in e]
Out[3]: [1.0]

Para su caso, será algo como esto.

In [4]: new_list = [float(y) for x in l for y in x]

21
Super útil! Deja en claro que los bucles (de arriba a abajo) se ordenan de izquierda a derecha en el generador. Esto no es obvio ya que en algunos (f(x) for x in l)lugares la segunda línea del equivalente for-loop de la izquierda.
user48956

Esta parece ser la única explicación que realmente me está afectando, ¡gracias!
Douglas Plumley

48
>>> l = [['40', '20', '10', '30'], ['20', '20', '20', '20', '20', '30', '20'], ['30', '20', '30', '50', '10', '30', '20', '20', '20'], ['100', '100'], ['100', '100', '100', '100', '100'], ['100', '100', '100', '100']]
>>> new_list = [float(x) for xs in l for x in xs]
>>> new_list
[40.0, 20.0, 10.0, 30.0, 20.0, 20.0, 20.0, 20.0, 20.0, 30.0, 20.0, 30.0, 20.0, 30.0, 50.0, 10.0, 30.0, 20.0, 20.0, 20.0, 100.0, 100.0, 100.0, 100.0, 100.0, 100.0, 100.0, 100.0, 100.0, 100.0, 100.0]

42

No estoy seguro de cuál es su salida deseada, pero si está utilizando la comprensión de la lista, el orden sigue el orden de los bucles anidados, que tiene al revés. Así que obtuve lo que creo que quieres con:

[float(y) for x in l for y in x]

El principio es: use el mismo orden que usaría al escribirlo como anidado para bucles.


esta debería ser la respuesta, ya que algunas veces no queremos poner entre corchetes el iteratool
zinc el

1
Esta puede no ser la respuesta correcta, ya que genera una lista no anidada, pero es lo que estaba buscando, especialmente el principio . ¡Gracias!
Rodrigo E. Principe

4

Como llegué un poco tarde aquí, pero quería compartir cómo funciona realmente la comprensión de listas, especialmente la comprensión de listas anidadas:

New_list= [[float(y) for x in l]

en realidad es lo mismo que:

New_list=[]
for x in l:
    New_list.append(x)

Y ahora la comprensión de la lista anidada:

[[float(y) for y in x] for x in l]

es igual que;

new_list=[]
for x in l:
    sub_list=[]
    for y in x:
        sub_list.append(float(y))

    new_list.append(sub_list)

print(new_list)

salida:

[[40.0, 20.0, 10.0, 30.0], [20.0, 20.0, 20.0, 20.0, 20.0, 30.0, 20.0], [30.0, 20.0, 30.0, 50.0, 10.0, 30.0, 20.0, 20.0, 20.0], [100.0, 100.0], [100.0, 100.0, 100.0, 100.0, 100.0], [100.0, 100.0, 100.0, 100.0]]

3

Si no le gustan las comprensiones de listas anidadas, también puede utilizar la función de mapa ,

>>> from pprint import pprint

>>> l = l = [['40', '20', '10', '30'], ['20', '20', '20', '20', '20', '30', '20'], ['30', '20', '30', '50', '10', '30', '20', '20', '20'], ['100', '100'], ['100', '100', '100', '100', '100'], ['100', '100', '100', '100']] 

>>> pprint(l)
[['40', '20', '10', '30'],
['20', '20', '20', '20', '20', '30', '20'],
['30', '20', '30', '50', '10', '30', '20', '20', '20'],
['100', '100'],
['100', '100', '100', '100', '100'],
['100', '100', '100', '100']]

>>> float_l = [map(float, nested_list) for nested_list in l]

>>> pprint(float_l)
[[40.0, 20.0, 10.0, 30.0],
[20.0, 20.0, 20.0, 20.0, 20.0, 30.0, 20.0],
[30.0, 20.0, 30.0, 50.0, 10.0, 30.0, 20.0, 20.0, 20.0],
[100.0, 100.0],
[100.0, 100.0, 100.0, 100.0, 100.0],
[100.0, 100.0, 100.0, 100.0]]

Su código genera objetos de mapa en lugar de listas: >>> float_l = [map(float, nested_list) for nested_list in l] [[<map at 0x47be9b0>], [<map at 0x47be2e8>], [<map at 0x47be4a8>], [<map at 0x47beeb8>], [<map at 0x484b048>], [<map at 0x484b0b8>]] pero al agregar una llamada adicional a la lista funciona como se esperaba: >>> float_l = [list(map(float, nested_list)) for nested_list in l]
pixelperfect

@pixelperfect que se debe al cambio ( mal informado ...) python3para devolver los generadores por falta de comprensión.
javadba

3

Tenía un problema similar que resolver, así que me encontré con esta pregunta. Hice una comparación de rendimiento de la respuesta de Andrew Clark y Narayan que me gustaría compartir.

La principal diferencia entre dos respuestas es cómo iteran sobre las listas internas. Uno de ellos usa un mapa incorporado , mientras que otro usa la comprensión de la lista. La función de mapa tiene una ligera ventaja de rendimiento en su comprensión de lista equivalente si no requiere el uso de lambdas . Entonces, en el contexto de esta pregunta, mapdebería funcionar un poco mejor que la comprensión de la lista.

Hagamos un punto de referencia de rendimiento para ver si es realmente cierto. Usé la versión 3.5.0 de Python para realizar todas estas pruebas. En el primer conjunto de pruebas, me gustaría mantener los elementos por lista en 10 y variar el número de listas de 10 a 100,000

>>> python -m timeit "[list(map(float,k)) for k in [list(range(0,10))]*10]"
>>> 100000 loops, best of 3: 15.2 usec per loop   
>>> python -m timeit "[[float(y) for y in x] for x in [list(range(0,10))]*10]"
>>> 10000 loops, best of 3: 19.6 usec per loop 

>>> python -m timeit "[list(map(float,k)) for k in [list(range(0,10))]*100]"
>>> 100000 loops, best of 3: 15.2 usec per loop
>>> python -m timeit "[[float(y) for y in x] for x in [list(range(0,10))]*100]"
>>> 10000 loops, best of 3: 19.6 usec per loop 

>>> python -m timeit "[list(map(float,k)) for k in [list(range(0,10))]*1000]"
>>> 1000 loops, best of 3: 1.43 msec per loop   
>>> python -m timeit "[[float(y) for y in x] for x in [list(range(0,10))]*1000]"
>>> 100 loops, best of 3: 1.91 msec per loop

>>> python -m timeit "[list(map(float,k)) for k in [list(range(0,10))]*10000]"
>>> 100 loops, best of 3: 13.6 msec per loop   
>>> python -m timeit "[[float(y) for y in x] for x in [list(range(0,10))]*10000]"
>>> 10 loops, best of 3: 19.1 msec per loop

>>> python -m timeit "[list(map(float,k)) for k in [list(range(0,10))]*100000]"
>>> 10 loops, best of 3: 164 msec per loop
>>> python -m timeit "[[float(y) for y in x] for x in [list(range(0,10))]*100000]"
>>> 10 loops, best of 3: 216 msec per loop

ingrese la descripción de la imagen aquí

En el siguiente conjunto de pruebas, me gustaría aumentar el número de elementos por lista a 100 .

>>> python -m timeit "[list(map(float,k)) for k in [list(range(0,100))]*10]"
>>> 10000 loops, best of 3: 110 usec per loop
>>> python -m timeit "[[float(y) for y in x] for x in [list(range(0,100))]*10]"
>>> 10000 loops, best of 3: 151 usec per loop

>>> python -m timeit "[list(map(float,k)) for k in [list(range(0,100))]*100]"
>>> 1000 loops, best of 3: 1.11 msec per loop
>>> python -m timeit "[[float(y) for y in x] for x in [list(range(0,100))]*100]"
>>> 1000 loops, best of 3: 1.5 msec per loop

>>> python -m timeit "[list(map(float,k)) for k in [list(range(0,100))]*1000]"
>>> 100 loops, best of 3: 11.2 msec per loop
>>> python -m timeit "[[float(y) for y in x] for x in [list(range(0,100))]*1000]"
>>> 100 loops, best of 3: 16.7 msec per loop

>>> python -m timeit "[list(map(float,k)) for k in [list(range(0,100))]*10000]"
>>> 10 loops, best of 3: 134 msec per loop
>>> python -m timeit "[[float(y) for y in x] for x in [list(range(0,100))]*10000]"
>>> 10 loops, best of 3: 171 msec per loop

>>> python -m timeit "[list(map(float,k)) for k in [list(range(0,100))]*100000]"
>>> 10 loops, best of 3: 1.32 sec per loop
>>> python -m timeit "[[float(y) for y in x] for x in [list(range(0,100))]*100000]"
>>> 10 loops, best of 3: 1.7 sec per loop

ingrese la descripción de la imagen aquí

Vamos a dar un paso valiente y modificar el número de elementos en las listas para que sea 1000

>>> python -m timeit "[list(map(float,k)) for k in [list(range(0,1000))]*10]"
>>> 1000 loops, best of 3: 800 usec per loop
>>> python -m timeit "[[float(y) for y in x] for x in [list(range(0,1000))]*10]"
>>> 1000 loops, best of 3: 1.16 msec per loop

>>> python -m timeit "[list(map(float,k)) for k in [list(range(0,1000))]*100]"
>>> 100 loops, best of 3: 8.26 msec per loop
>>> python -m timeit "[[float(y) for y in x] for x in [list(range(0,1000))]*100]"
>>> 100 loops, best of 3: 11.7 msec per loop

>>> python -m timeit "[list(map(float,k)) for k in [list(range(0,1000))]*1000]"
>>> 10 loops, best of 3: 83.8 msec per loop
>>> python -m timeit "[[float(y) for y in x] for x in [list(range(0,1000))]*1000]"
>>> 10 loops, best of 3: 118 msec per loop

>>> python -m timeit "[list(map(float,k)) for k in [list(range(0,1000))]*10000]"
>>> 10 loops, best of 3: 868 msec per loop
>>> python -m timeit "[[float(y) for y in x] for x in [list(range(0,1000))]*10000]"
>>> 10 loops, best of 3: 1.23 sec per loop

>>> python -m timeit "[list(map(float,k)) for k in [list(range(0,1000))]*100000]"
>>> 10 loops, best of 3: 9.2 sec per loop
>>> python -m timeit "[[float(y) for y in x] for x in [list(range(0,1000))]*100000]"
>>> 10 loops, best of 3: 12.7 sec per loop

ingrese la descripción de la imagen aquí

De estas pruebas podemos concluir que maptiene un beneficio de rendimiento sobre la comprensión de la lista en este caso. Esto también es aplicable si usted está tratando de yeso para cualquiera into str. Para un pequeño número de listas con menos elementos por lista, la diferencia es insignificante. Para listas más grandes con más elementos por lista, a uno le gustaría usar en maplugar de la comprensión de la lista, pero depende totalmente de las necesidades de la aplicación.

Sin embargo, personalmente considero que la comprensión de la lista es más legible e idiomática que map. Es un estándar de facto en python. Por lo general, las personas son más competentes y cómodas (especialmente principiantes) en el uso de la comprensión de listas que map.


2

Sí, puedes hacerlo con dicho código:

l = [[float(y) for y in x] for x in l]

[float(y) for y in x for x in l]esto daría como resultado un montón de 100 con una suma de 2400.
Boy Pasmo

2

Este problema se puede resolver sin usar for loop. El código de línea simple será suficiente para esto. El uso de Mapa anidado con la función lambda también funcionará aquí.

l = [['40', '20', '10', '30'], ['20', '20', '20', '20', '20', '30', '20'], ['30', '20', '30', '50', '10', '30', '20', '20', '20'], ['100', '100'], ['100', '100', '100', '100', '100'], ['100', '100', '100', '100']]

map(lambda x:map(lambda y:float(y),x),l)

Y la lista de resultados sería la siguiente:

[[40.0, 20.0, 10.0, 30.0], [20.0, 20.0, 20.0, 20.0, 20.0, 30.0, 20.0], [30.0, 20.0, 30.0, 50.0, 10.0, 30.0, 20.0, 20.0, 20.0], [100.0, 100.0], [100.0, 100.0, 100.0, 100.0, 100.0], [100.0, 100.0, 100.0, 100.0]]

1
¿Lambdas tiene algún beneficio de rendimiento sobre las soluciones de @Andrew Clark o Harry Binswanger (la comprensión más vasta de la lista)? Como las lambdas parecen más difíciles de leer.
StefanJCollier

0

La mejor manera de hacer esto en mi opinión es usar el itertoolspaquete de Python .

>>>import itertools
>>>l1 = [1,2,3]
>>>l2 = [10,20,30]
>>>[l*2 for l in itertools.chain(*[l1,l2])]
[2, 4, 6, 20, 40, 60]


-2
    deck = [] 
    for rank in ranks:
        for suit in suits:
            deck.append(('%s%s')%(rank, suit))

Esto se puede lograr utilizando la comprensión de la lista:

[deck.append((rank,suit)) for suit in suits for rank in ranks ]

1
Esto no parece abordar la pregunta en la parte superior en absoluto. Tenga en cuenta que todo lo publicado como respuesta debe ser un intento de responder a la pregunta en la que está publicado.
Baum mit Augen

Si bien este fragmento de código puede resolver la pregunta, incluir una explicación realmente ayuda a mejorar la calidad de su publicación. Recuerde que está respondiendo la pregunta para los lectores en el futuro, y que esas personas podrían no conocer los motivos de su sugerencia de código. Por favor, también trate de no saturar su código con comentarios explicativos, ¡esto reduce la legibilidad tanto del código como de las explicaciones!
Filnor

Anidado para el bucle usando la comprensión de la lista,
ADITYA KUMAR

1
Ok, aparentemente, este es un intento de responder la pregunta. Sin embargo, esto parece tratarse de un escenario completamente diferente que en OP, ni siquiera se trata con listas anidadas como entrada, e incluso si cambia que su sugerencia es más o menos lo que OP ya intentó. Además, no veo cómo un ejemplo sobre tarjetas ayuda cuando la pregunta es sobre la conversión de cadenas a flotantes.
Baum mit Augen
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.