2009-05-10 13 views
28

Spesso faccio vettoriale aggiunta di liste Python.Aggiunta vettoriale concisa in Python?

Esempio: ho due liste come questi:

a = [0.0, 1.0, 2.0] 
b = [3.0, 4.0, 5.0] 

io ora voglio aggiungere b per un per ottenere il risultato a = [3.0, 5.0, 7.0].

solito finisce per fare come questo:

a[0] += b[0] 
a[1] += b[1] 
a[2] += b[2] 

C'è qualche, modo standard efficace di fare questo con meno di battitura?

AGGIORNAMENTO: Si può presumere che gli elenchi siano di lunghezza 3 e contengano galleggianti.

risposta

27

non credo che troverete una soluzione più veloce dei 3 importi proposti nella domanda. I vantaggi di numpy sono visibili con vettori più grandi e anche se hai bisogno di altri operatori. numpy è particolarmente utile con le matrici, la strega è un trucco da fare con le liste python.

Ancora, un altro modo per farlo: D

In [1]: a = [1,2,3] 

In [2]: b = [2,3,4] 

In [3]: map(sum, zip(a,b)) 
Out[3]: [3, 5, 7] 

Edit: è anche possibile utilizzare l'izip da itertools, una versione generatore di zip

In [5]: from itertools import izip 

In [6]: map(sum, izip(a,b)) 
Out[6]: [3, 5, 7] 
+0

Un fatto divertente: 'map' viene fornito con la funzionalità' zip' inclusa. Questo permette di dire 'map (operator.add, a, b)' – Kos

0

È possibile creare una funzione che recuperi le dimensioni della matrice, la attraversi e crei una matrice di restituzione che restituisce.

+0

Grazie, ma che non sembra molto efficiente. –

+0

@kotlinski. Che cosa? La dimensione dell'array è len (array) che non è una "computazione" ma un attributo della lista. Looping è certamente meno digitante di un [0] + = b [0] ... a [999] + = b [999]. Anche meno soggetto a errori. Anche più ovvio. Darò un po 'di efficienza per evitare errori di digitazione. –

+0

Penso che il mio problema principale sarebbe quello di creare e restituire un elenco, che in questo caso non sarebbe necessario. Altrimenti, sì, non è peggio dell'altra idea. –

9

ne dite di questo:

a = [x+y for x,y in zip(a,b)] 
+2

+1 ma funziona solo quando gli elenchi hanno le stesse dimensioni. izip_longest con un valore zip pari a 0 se non sono sempre della stessa dimensione –

+0

Bello, ma non risparmia molto digitazione e il codice originale è oltre tre volte più veloce. –

+0

@ kotlinski-hmm, hai ragione –

3

[a [x] + b [x] per x nell'intervallo (0, len (a))]

+0

questo è esattamente ciò che OP sta già facendo. – SilentGhost

+2

Questa è la versione meno tipografica, per favore sii costruttivo nella tua critica. La tua critica cieca non aiuta nessuno. – ismail

+1

non è né standard né efficiente. è abbastanza costruttivo per te? – SilentGhost

29

Se avete bisogno di efficienti aritmetica vettoriale, provare Numpy.

>>> import numpy 
>>> a=numpy.array([0,1,2]) 
>>> b=numpy.array([3,4,5]) 
>>> a+b 
array([3, 5, 7]) 
>>> 

Or (grazie, Andrew Jaffe),

>>> a += b 
>>> a 
array([3, 5, 7]) 
>>> 
+0

nb. OP vuole un + = b, davvero - guarda la mia risposta, qui sotto! ;-) –

+1

Sembra un buon modo per risparmiare la digitazione, ma non mi piace che aggiunga una dipendenza ed è tre volte più lento del codice originale. –

5

Oppure, se siete disposti ad utilizzare una libreria esterna (e di lunghezza fissa array), utilizzare numpy, che ha "+ = "e operazioni correlate per le operazioni sul posto.

import numpy as np 
a = np.array([0, 1, 2]) 
b = np.array([3, 4, 5]) 
a += b 
30

Mentre numerico è eccellente, e le soluzioni list-comprensione OK se effettivamente voleva creare un nuovo elenco, sono sorpreso nessuno ha chiesto "un modo ovvio per farlo" - un semplice for ciclo! Miglior:

for i, bi in enumerate(b): a[i] += bi 

anche OK, un po 'sorta:

for i in xrange(len(a)): a[i] += b[i] 
+0

+1, questa è la soluzione più ovvia per me. – Kiv

+1

Più veloce delle altre soluzioni, ma ancora solo a metà della velocità. –

0

Un miglioramento (meno consumo di memoria) della lista di comprensione

importazione itertools a = [x + y per x, y in itertools.izip (a, b)]

In realtà se non si è sicuri che si consumerà, andrei anche con l'espressione del generatore:

(x + y per x, y in itertools.izip (a, b))

13

Se si pensa Numpy è eccessivo, questo dovrebbe essere veramente veloce, perché questo codice viene eseguito in puro C (map() e __add__() sono entrambi implementata direttamente in C):

a = [1.0,2.0,3.0] 
b = [4.0,5.0,6.0] 

c = map(float.__add__, a, b) 

oppure, in alternativa, se non si conoscono i tipi nella lista:

import operator 
c = map(operator.add, a, b) 
+0

Questa è una risposta davvero interessante, ma sfortunatamente tre volte più lenta del codice originale. –

+0

Questo mi sorprende davvero. Almeno la prima versione dovrebbe essere più veloce. Forse è solo più veloce se hai liste più grandi. –

+3

Dai un'occhiata al modulo operatore. Puoi semplicemente usare 'operator.add'. – schlamar

1

Se sei dopo conciso, provare ...

vectors = [[0.0, 1.0, 2.0],[3.0, 4.0, 5.0]] 
[sum(col) for col in zip(*vectors)] 

Anche se non posso parlare per la p erformance di questo.

0
list(map(lambda x:x[0]+x[1], zip(a,b))) 
+0

Puoi spiegare questa soluzione un po '? – dethtron5000

+0

Sicuro :) Prima di tutto, ho applicato ** la funzione zip ** che restituirà un elenco di tuple, ad es. se 'a = [1,2,3]' e 'b = [4,5,6]', 'zip (a, b)' restituisce '[(1,4), (2,5), (3 , 6)] '. Successivamente, ho applicato ** map ** in questo risultato, ** map ** function ha una funzione come primo argomento e un iterable come secondo argomento e applica tale funzione a ogni elemento di questo iterable. In questo caso, l'iterabile è 'zip (a, b)' e la funzione è 'lambda x: x [0] + x [1]', riceve un oggetto 'x' come argomento e restituisce' x [0 ] + x [1] '. 'map()' restituisce una lista in python2.In python3 restituisce un oggetto mappa, quindi ho usato 'list()' –

1

Per il caso generale di avere una lista di liste che si possa fare qualcosa di simile:

In [2]: import numpy as np 

In [3]: a = np.array([[1, 1, 1], [2, 2, 2], [3, 3, 3],[4, 5, 6]]) 

In [4]: [sum(a[:,i]) for i in xrange(len(a[0]))] 
Out[4]: [10, 11, 12] 
0
a = map(lambda x, y: x + y, a, b)