2012-06-21 18 views
7

Ad esempio:Due incarichi in lista unica pitone comprensione

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

sarebbe più efficace di combinare le list comprehension in uno (se possibile) se le dimensioni di un è grande? Se è così, come lo fai?

Qualcosa di simile,

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

che non funziona. Se utilizzare la comprensione delle liste non è più efficiente dal punto di vista computazionale rispetto all'utilizzo di un ciclo normale per ciclo, fammelo sapere. Grazie.

+0

L'ultima lista di comprensione restituisce un elenco di tuple, che quindi si tenta di assegnare a una singola tupla, motivo per cui ciò non riesce. Potresti appiattirlo in due elenchi separati in seguito, ma non posso dire quale sia più efficiente. –

+1

puoi pensare di convertire una lista di coppie in una coppia di liste come [trasporre una matrice 2D] (http://stackoverflow.com/q/4937491/4279). – jfs

+0

@ user1473483 cosa dire 'x, y = [[2 * i per i in a], [3 * i per i in a]]' ?? –

risposta

9

caso di dubbi sulla efficienza utilizzare il modulo timeit, è sempre facile da usare:

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) 

I risultati sembrano essere coerenti nella punta alla prima opzione, come il più veloce.

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

Questo è un ottimo punto: direi che la prima opzione è probabilmente anche la più chiara come il più veloce. L'unica volta in cui questo sarebbe preferibile sarebbe se 'aRange' fosse un generatore che si esauriva, dove l'uso di questo metodo evitava di dover usare' tee() 'o una lista temporanea. –

12

Si desidera utilizzare the zip() builtin con l'operatore stella per fare ciò. zip() normalmente si trasforma in elenchi in un elenco di coppie, se usato in questo modo, scompatta: prende un elenco di coppie e lo divide in due elenchi.

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

Nota che non sono sicuro che questo sia davvero più efficiente in un modo che sta per avere importanza.

+0

Qui è possibile utilizzare un generatore anziché la comprensione degli elenchi. 'x, y = zip (* ((2 * i, 3 ​​* i) per i in a))' (se fa alcuna differenza) – jadkik94

+0

@ jadkik94 Dato che si stanno usando tutti i valori comunque con zip, è praticamente non farò alcuna differenza, anche se quello che dici è vero. –

+0

@ jadkik94 che sembra essere l'opzione più lenta, controlla la mia risposta. – Trufa

Problemi correlati