Python Element-Wise Tuple Operations Like Sum

Python element-wise tuple operations like sum

import operator
tuple(map(operator.add, a, b))

Adding two tuples elementwise

Zip them, then sum each tuple.

[sum(x) for x in zip(a,b)]

EDIT : Here's a better, albeit more complex version that allows for weighting.

from itertools import starmap, islice, izip

a = [1, 2, 3]
b = [3, 4, 5]
w = [0.5, 1.5] # weights => a*0.5 + b*1.5

products = [m for m in starmap(lambda i,j:i*j, [y for x in zip(a,b) for y in zip(x,w)])]

sums = [sum(x) for x in izip(*[islice(products, i, None, 2) for i in range(2)])]

print sums # should be [5.0, 7.0, 9.0]

sum each value in a list of tuples

Use zip() and sum():

In [1]: l = [(1, 2), (3, 4), (5, 6), (7, 8), (9, 0)]

In [2]: [sum(x) for x in zip(*l)]
Out[2]: [25, 20]

or:

In [4]: map(sum, zip(*l))
Out[4]: [25, 20]

timeit results:

In [16]: l = [(1, 2), (3, 4), (5, 6), (7, 8), (9, 0)]*1000

In [17]: %timeit [sum(x) for x in zip(*l)]
1000 loops, best of 3: 1.46 ms per loop

In [18]: %timeit [sum(x) for x in izip(*l)] #prefer itertools.izip
1000 loops, best of 3: 1.28 ms per loop

In [19]: %timeit map(sum, zip(*l))
100 loops, best of 3: 1.48 ms per loop

In [20]: %timeit map(sum, izip(*l)) #prefer itertools.izip
1000 loops, best of 3: 1.29 ms per loop

Elementwise operations over tuples in Python

map function

>>> a = (1, 2, 4)
>>> b = (1.1, 2.1, 4.1)
>>> map(lambda a,b: 100*abs(a-b)/a < 3, a, b)
[False, False, True]

EDIT

of course instead of map, you can use list comprehensions, like BrenBarn did http://docs.python.org/tutorial/datastructures.html#nested-list-comprehensions

EDIT 2 zip removed, thanks for DSM to point it out that zip is not needed

How can I pairwise sum two equal-length tuples

tuple(map(lambda (x, y): x + y, zip((0,-1,7), (3,4,-7))))

If you prefer to avoid map and lambda then you can do:

tuple(x + y for x,y in zip((0,-1,7), (3,4,-7)))

EDIT: As one of the answers pointed out, you can use sum instead of explicitly splitting the tuples returned by zip. Therefore you can rewrite the above code sample as shown below:

tuple(sum(t) for t in zip((0,-1,7), (3,4,-7)))

Reference: zip, map, sum.

Element-wise addition of 2 lists?

Use map with operator.add:

>>> from operator import add
>>> list( map(add, list1, list2) )
[5, 7, 9]

or zip with a list comprehension:

>>> [sum(x) for x in zip(list1, list2)]
[5, 7, 9]

Timing comparisons:

>>> list2 = [4, 5, 6]*10**5
>>> list1 = [1, 2, 3]*10**5
>>> %timeit from operator import add;map(add, list1, list2)
10 loops, best of 3: 44.6 ms per loop
>>> %timeit from itertools import izip; [a + b for a, b in izip(list1, list2)]
10 loops, best of 3: 71 ms per loop
>>> %timeit [a + b for a, b in zip(list1, list2)]
10 loops, best of 3: 112 ms per loop
>>> %timeit from itertools import izip;[sum(x) for x in izip(list1, list2)]
1 loops, best of 3: 139 ms per loop
>>> %timeit [sum(x) for x in zip(list1, list2)]
1 loops, best of 3: 177 ms per loop

Summing up two lists of tuples on a condition

An obvious solution is to create a result dictionary, then add all values from the first list and then all values from the second list:

from collections import defaultdict

result = defaultdict(int)
for key, value in list1:
result[key] += value
for key, value in list2:
result[key] += value

# convert dictionary-like to list of tuples if you want
result = list(result.items())

Using a dictionary as result spares you from doing a linear search to find the key to which to add a value (leading to an overall quadratic complexity), and a defaultdict in particular spares you from doing

if key not in result:
result[key] = 0

to initialize the result before adding the first value.

You can generalize this to any number of input lists by using itertools.chain:

from collections import defaultdict
from itertools import chain

input_lists = [list1, list2]

result = defaultdict(int)
for key, value in chain.from_iterable(input_lists):
result[key] += value

Visually there is now only one for loop but under the hoods it is doing the same.

How to add with tuples

Do you want to do element-wise addition, or to append the tuples? By default python does

(1,2)+(3,4) = (1,2,3,4)

You could define your own as:

def myadd(x,y):
z = []
for i in range(len(x)):
z.append(x[i]+y[i])
return tuple(z)

Also, as @delnan's comment makes it clear, this is better written as

def myadd(xs,ys):
return tuple(x + y for x, y in izip(xs, ys))

or even more functionally:

myadd = lambda xs,ys: tuple(x + y for x, y in izip(xs, ys))

Then do

if( b < a) return myadd((1,0),foo(a-b,b))


Related Topics



Leave a reply



Submit