python - tuplas - ¿Enumera la comprensión en una lista anidada?
listas anidadas python (11)
Aquí es cómo lo haría con una lista anidada de comprensión:
[[float(y) for y in x] for x in l]
Esto le daría una lista de listas, similar a lo que comenzó, excepto con flotadores en lugar de cadenas. Si quieres una lista plana, entonces deberías usar [float(y) for x in l for y in x]
.
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 utilizando la comprensión de listas anidadas, verdad?
lo que hice fue:
[float(y) for y in x for x in l]
Pero luego el resultado es un montón de 100 con la suma de 2400.
cualquier solución, una explicación sería muy apreciada. ¡Gracias!
Como llegué un poco tarde aquí, quería compartir cómo realmente funciona la comprensión de listas, especialmente la comprensión de listas anidadas:
New_list= [[float(y) for x in l]
es en realidad 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 lo mismo 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]]
Este problema se puede resolver sin usar for loop. Para esto, bastará con un solo código de línea. El uso de Nested Map 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 salida 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]]
La mejor manera de hacer esto en mi opinión es usar el paquete de itertools
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]
No estoy seguro de cuál es el resultado deseado, pero si usa la comprensión de listas, 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 para escribirlo como anidado para bucles.
Sí, puedes hacerlo con dicho código:
l = [[float(y) for y in x] for x in l]
Si no le gustan las comprensiones de listas anidadas, puede hacer uso de la función de map también,
>>> 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]]
Tuve un problema similar para 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 el map incorporado, mientras que el otro usa la lista de comprensión. La función de mapa tiene una ligera ventaja de rendimiento para su comprensión de lista equivalente si no requiere el uso de lambdas . Entonces, en el contexto de esta pregunta, el map
debería funcionar un poco mejor que la lista de comprensión.
Hagamos un punto de referencia de rendimiento para ver si realmente es cierto. Utilicé la versión 3.5.0 de python para realizar todas estas pruebas. En la primera serie de pruebas me gustaría mantener los elementos por lista en 10 y variar el número de listas de 10-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
En la próxima serie 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
Vamos a dar un valiente paso y modificar la cantidad de elementos en las listas para que sean 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
A partir de estas pruebas, podemos concluir que el map
tiene un beneficio de rendimiento sobre la comprensión de la lista en este caso. Esto también es aplicable si intentas convertir a int
o str
. Para un número pequeño 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 el map
lugar de la comprensión de la lista, pero depende totalmente de las necesidades de la aplicación.
Sin embargo, personalmente encuentro que la comprensión de la lista es más legible e idiomática que el map
. Es un estándar de facto en python. Por lo general, las personas son más competentes y cómodas (especialmente para principiantes) en el uso de la lista de comprensión que en el map
.
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]
#Which can be written in single line as
In [4]: [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[4]: [1.0]
deck = []
for rank in ranks:
for suit in suits:
deck.append((''%s%s'')%(rank, suit))
Esto se puede lograr utilizando la lista de comprensión:
[deck.append((rank,suit)) for suit in suits for rank in ranks ]
>>> 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]