Concise vector adding in Python? [duplicate]
Asked Answered
V

13

50

I often do vector addition of Python lists.

Example: I have two lists like these:

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

I now want to add b to a to get the result a = [3.0, 5.0, 7.0].

Usually I end up doing like this:

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

Is there some efficient, standard way to do this with less typing?

UPDATE: It can be assumed that the lists are of length 3 and contain floats.

Vernalize answered 10/5, 2009 at 11:5 Comment(0)
S
50

I don't think you will find a faster solution than the 3 sums proposed in the question. The advantages of numpy are visible with larger vectors, and also if you need other operators. numpy is specially useful with matrixes, witch are trick to do with python lists.

Still, yet another way to do it :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: you can also use the izip from itertools, a generator version of zip

In [5]: from itertools import izip

In [6]: map(sum, izip(a,b))
Out[6]: [3, 5, 7]
Shanklin answered 10/5, 2009 at 22:54 Comment(1)
Fun fact: map comes with zip functionality included. This allows to say map(operator.add, a, b)Trimeter
S
52

If you need efficient vector arithmetic, try Numpy.

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

Or (thanks, Andrew Jaffe),

>>> a += b
>>> a
array([3, 5, 7])
>>> 
Swizzle answered 10/5, 2009 at 11:21 Comment(2)
nb. OP wants a+=b, really -- see my answer, below! ;-)Salvation
Looks like a good way to save typing, but I don't like that it adds a dependency and is three times slower than the original code.Vernalize
S
50

I don't think you will find a faster solution than the 3 sums proposed in the question. The advantages of numpy are visible with larger vectors, and also if you need other operators. numpy is specially useful with matrixes, witch are trick to do with python lists.

Still, yet another way to do it :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: you can also use the izip from itertools, a generator version of zip

In [5]: from itertools import izip

In [6]: map(sum, izip(a,b))
Out[6]: [3, 5, 7]
Shanklin answered 10/5, 2009 at 22:54 Comment(1)
Fun fact: map comes with zip functionality included. This allows to say map(operator.add, a, b)Trimeter
S
35

While Numeric is excellent, and list-comprehension solutions OK if you actually wanted to create a new list, I'm surprised nobody suggested the "one obvious way to do it" -- a simple for loop! Best:

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

Also OK, kinda sorta:

for i in xrange(len(a)): a[i] += b[i]
Spermary answered 10/5, 2009 at 13:15 Comment(2)
+1, this is the obvious solution to me.Unruh
Faster than the other solutions, but still only half as fast.Vernalize
L
20

If you think Numpy is overkill, this should be really fast, because this code runs in pure C (map() and __add__() are both directly implemented in C):

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

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

Or alternatively, if you don't know the types in the list:

import operator
c = map(operator.add, a, b)
Ledbetter answered 10/5, 2009 at 17:58 Comment(6)
This is a really cool answer, but unfortunately three times slower than the original code.Vernalize
This really suprises me. At least the first version should be faster. Maybe it's only faster if you have larger lists.Sakhuja
Have a look at the operator module. You can can just use operator.add.Giule
@schlamar: Changed the answer. Thanks.Sakhuja
@GeorgSchölly operator.add should be even fasterCarpi
+1 for operator.add. Also, in Python 3 map produces a map object, not a list. So the correct solution would be c = list(map(operator.add, a, b)).Lelialelith
B
12

How about this:

a = [x+y for x,y in zip(a,b)]
Bibelot answered 10/5, 2009 at 11:9 Comment(8)
+1 but this will only work when the lists are of the same size. izip_longest with a zip value of 0 if they are not always of the same sizeBerrios
Nice, but it doesn't save a lot of typing, and the original code is over three times faster.Vernalize
@kotlinski- hmm, you are rightBerrios
what size of input lists do you use to check performance?Maleficent
who cares about 3? how do you type it for 100 items?Maleficent
Well, three is common for representing vertexes in three dimensions :)Vernalize
well if you want to know how sum two lists of length three pair-wise then you should have explicitly stated that. your method might be the fastest one, but your question is too localized then.Maleficent
Sorry, I updated the problem description now.Vernalize
S
8

Or, if you're willing to use an external library (and fixed-length arrays), use numpy, which has "+=" and related operations for in-place operations.

import numpy as np
a = np.array([0, 1, 2])
b = np.array([3, 4, 5])
a += b
Salvation answered 10/5, 2009 at 11:21 Comment(0)
B
3

[a[x] + b[x] for x in range(0,len(a))]

Bair answered 10/5, 2009 at 11:11 Comment(6)
that's exactly what OP is already doing.Maleficent
This is the less typing version, please be constructive in your critism. Your blind critism is not helping anyone.Bair
this is neither standard nor efficient. is that constructive enough for you?Maleficent
What part of list comprehension & range is not standard enough for you? List comprehensions are efficient, why you think its inefficient?Bair
Chill. Please do something like measure the performance and compare or cite references.Agadir
about 30 % slower comparing to Nadia's version on my machine.Maleficent
D
2

For the general case of having a list of lists you could do something like this:

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]
Dunedin answered 2/9, 2015 at 16:41 Comment(0)
C
1

If you're after concise, try...

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

Though I can't speak for the performance of this.

Coricoriaceous answered 5/6, 2014 at 20:52 Comment(0)
A
1
list(map(lambda x:x[0]+x[1], zip(a,b)))
Allspice answered 30/4, 2015 at 23:50 Comment(2)
Can you explain this solution a bit?Ungulate
Sure :) First of all, I applied zip function that will return a list of tuples, e.g. if a=[1,2,3] and b=[4,5,6], zip(a,b) returns [(1,4), (2,5), (3,6)]. After that, I applied map in this result, map function takes a function as first argument and an iterable as second argument and it applies that function to every item of this iterable. In this case, the iterable is zip(a,b) and the function is lambda x: x[0]+x[1], it receives an item x as argument and it returns x[0]+x[1]. map() returns a list in python2.In python3 it returns a map object, so I used list()Locule
F
1
a = map(lambda x, y: x + y, a, b)
Festatus answered 9/8, 2016 at 22:1 Comment(0)
T
0

You could create a function that gets the size of the array, loops through it and creating a return array which it returns.

Threadfin answered 10/5, 2009 at 11:7 Comment(5)
Thanks, but that doesn't seem very efficient.Vernalize
@kotlinski. What? Size of the array is len(array) which is not a "computation" but an attribute of the list. Looping is certainly less typing than a[0]+=b[0]... a[999]+=b[999]. Also less error-prone. Also more obvious. I'll give up a little efficiency to prevent errors from mistyping.Agadir
I think my main gripe would be creating and returning a list, which would not be necessary in this case. Otherwise, yes, it's not worse than the other idea.Vernalize
I only said return an array/list is because i thought you wanted that.Himes
"to get the result a = [3.0, 5.0, 7.0]."Himes
R
0

An improvement (less memory consumption) of the comprehension list

import itertools a = [x+y for x,y in itertools.izip(a,b)]

Actually if you are not sure that a will be consume then I would even go with generator expression:

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

Restricted answered 10/5, 2009 at 17:43 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.