2012-06-21 23 views
7

Por ejemplo:dos asignaciones de lista única pitón comprensión

a = [1,2,3] 
x = [2*i for i in a] 
y = [3*i for i in a] 

¿Sería más eficiente de combinar las listas por comprensión en uno (si es posible) si el tamaño de una es grande? Si es así, ¿cómo haces esto?

Algo así como,

x,y = [2*i, 3*i for i in a] 

que no funciona. Si el uso de la lista de comprensión no es más eficiente desde el punto de vista informático que utilizar un ciclo for normal, házmelo saber también. Gracias.

+0

La última lista de comprensión devuelve una lista de tuplas, que luego intenta asignar a una sola tupla, por lo que esto falla. Podría aplanar esto en dos listas separadas después, pero no puedo decir cuál es más eficiente. –

+1

puede pensar en convertir una lista de pares en un par de listas como [transposición de una matriz 2D] (http://stackoverflow.com/q/4937491/4279). – jfs

+0

@ user1473483 ¿qué pasa con 'x, y = [[2 * i para i en a], [3 * i para i en a]]' ?? –

Respuesta

9

En caso de duda acerca de la eficiencia de utilizar el módulo timeit, siempre es fácil de usar:

import timeit 

def f1(aRange): 
    x = [2*i for i in aRange] 
    y = [3*i for i in aRange] 
    return x,y 

def f2(aRange): 
    x, y = zip(*[(2*i, 3*i) for i in aRange]) 
    return x,y 

def f3(aRange): 
    x, y = zip(*((2*i, 3*i) for i in aRange)) 
    return x,y 

def f4(aRange): 
    x = [] 
    y = [] 
    for i in aRange: 
     x.append(i*2) 
     y.append(i*3) 
    return x,y 

print "f1: %f" %timeit.Timer("f1(range(100))", "from __main__ import f1").timeit(100000) 
print "f2: %f" %timeit.Timer("f2(range(100))", "from __main__ import f2").timeit(100000) 
print "f3: %f" %timeit.Timer("f3(range(100))", "from __main__ import f3").timeit(100000) 
print "f4: %f" %timeit.Timer("f4(range(100))", "from __main__ import f4").timeit(100000) 

Los resultados parecen ser consistentes en señalar a la primera opción como la más rápida.

f1: 2.127573 
f2: 3.551838 
f3: 3.859768 
f4: 4.282406 
+1

Este es un muy buen punto. Yo diría que la primera opción es probablemente la más clara también. como el más rápido. El único momento en el que esto sería preferido sería si 'aRange' fuera un generador que se agotara, donde el uso de este método evitaría tener que usar' tee() 'o una lista temporal. –

12

Quiere utilizar the zip() builtin con el operador de estrella para hacer esto. zip() normalmente convierte listas en una lista de pares, cuando se usa de esta manera, se descomprime, tomando una lista de pares y dividiéndola en dos listas.

>>> a = [1, 2, 3] 
>>> x, y = zip(*[(2*i, 3*i) for i in a]) 
>>> x 
(2, 4, 6) 
>>> y 
(3, 6, 9) 

Tenga en cuenta que no estoy seguro de que esto sea realmente más eficiente de una manera que va a importar.

+0

Puede usar un generador en lugar de la lista de comprensión aquí. 'x, y = zip (* ((2 * i, 3 ​​* i) para i en a))' (si hace alguna diferencia) – jadkik94

+0

@ jadkik94 Como va a usar todos los valores de todos modos con zip, es prácticamente no hará ninguna diferencia, aunque lo que dices es verdad. –

+0

@ jadkik94 que parece ser la opción más lenta, verifique mi respuesta. – Trufa