23

I was just wondering if there was an especially pythonic way of adding two tuples elementwise?

So far (a and b are tuples), I have

map(sum, zip(a, b))

My expected output would be:

(a[0] + b[0], a[1] + b[1], ...)

And a possible weighing would be to give a 0.5 weight and b 0.5 weight, or so on. (I'm trying to take a weighted average).

Which works fine, but say I wanted to add a weighting, I'm not quite sure how I would do that.

Thanks

James
  • 2,635
  • 5
  • 23
  • 30
  • What's your expected output then? – msvalkon May 14 '13 at 16:46
  • 1
    You *are* processing your `a` and `b` tuples element wise. You can also do `tuple(sum(aa, bb) for aa, bb in zip(a, b))` to unpack the two elements into separate variables. What would your weighting formula be? – Martijn Pieters May 14 '13 at 16:46
  • And instead of just `sum(i)` (or `sum(aa, bb)` for that matter), you can use a *different* expression to create other elements. Including a tuple with both the sum and other values: `(sum(aa, bb), aa / bb)` for example. – Martijn Pieters May 14 '13 at 16:47
  • You can define your own function that incorporates weighting, instead of using `sum` – qwwqwwq May 14 '13 at 16:48
  • Ok, but is there a way to do this without using another function? (As sum should be inherently faster, because it pushes the addition down to c-code, right?) – James May 14 '13 at 16:51
  • I imagine numpy has tuple addition, and probably weighted averages. – Waleed Khan May 14 '13 at 16:54
  • 1
    Possible duplicate of [Adding Values From Tuples of Same Length](http://stackoverflow.com/questions/1169725/adding-values-from-tuples-of-same-length) – jeromej Jun 04 '16 at 19:25

5 Answers5

28

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]
Chris Doggett
  • 19,959
  • 4
  • 61
  • 86
7

If you do not mind the dependency, you can use numpy for elementwise operations on arrays

>>> import numpy as np
>>> a = np.array([1, 2, 3])
>>> b = np.array([3, 4, 5])
>>> a + b
array([4, 6, 8])
D R
  • 21,936
  • 38
  • 112
  • 149
6
>>> a = (1, 2, 3)
>>> b = (4, 5, 6)
>>> def averageWeightedSum(args):
        return sum(args) / len(args)
>>> tuple(map(averageWeightedSum, zip(a, b)))
(2.5, 3.5, 4.5)

An alternative would be to apply the weights first. This would also allow you to have different weights:

>>> from operator import mul
>>> weights = (0.3, 0.7)
>>> tuple(sum(map(mul, x, weights)) for x in zip(a, b))
(3.0999999999999996, 4.1, 5.1)
>>> weights = (0.5, 0.5)
>>> tuple(sum(map(mul, x, weights)) for x in zip(a, b))
(2.5, 3.5, 4.5)
poke
  • 369,085
  • 72
  • 557
  • 602
2

Take the formula for the weighted sum of one pair of coordinates, and form a tuple with an iterator over each pair (note the two variables after the for):

tuple(0.5*an + 0.5*bn for an, bn in zip(a, b))

This keeps it simple and readable as a one-liner. Of course if your "weighted sum" is a complicated function, you'd define it as a separate function first.

alexis
  • 48,685
  • 16
  • 101
  • 161
  • 1
    `tuple(sum(x) for x in zip(a, b))` **is better ... and** `tuple(map(sum, zip(a, b)))` **is even better**. – Nawaz Apr 26 '16 at 08:53
  • @Nawaz, why is it better? I say i`sum()` is worse. If you want a weighted sum, `sum()` is useless. Also, it's a matter of taste but I find `sum()` more appropriate when there is an indefinite number of summands -- here it's always two terms being added. To each their own, I guess, but don't forget that the weighted sum is part of the OP's question. – alexis Apr 26 '16 at 14:50
  • Ohh.. I didnt notice the weight. But then the first form can still work as: `tuple(0.5 * sum(x) for x in zip(a, b))`. It is almost same as yours, just that it is more functional (and probably pythonic too). – Nawaz Apr 26 '16 at 15:07
  • Not at all, you're missing the point. Giving both parts the same weight is nonsense, you might as well divide the sum by 2. The OP chose a poor "possible weighing" as the example. A better one would have been `0.7*a + 0.3*b`. But write your own code however you like. – alexis Apr 27 '16 at 19:42
  • Now, you have changed the question. ;-) (because "Giving both parts the same weight is nonsense" is not necessarily true, where it is not true, my solution works and seems better :P). – Nawaz Apr 28 '16 at 02:16
  • I haven't changed anything-- read the question. I understand _you_ like your solution better, you've made that clear. (See also poke's answer, should you _really_ want to use `sum` for addition with weights.) De gustibus et coloribus... – alexis Apr 28 '16 at 13:46
  • Please see things in context. If the weights are same, as YOU have used in your answer, then my solution works great (and it is *cute* as well :P). Now, whether that is going to work or not if the weights are different, then that is a different question altogether. – Nawaz Apr 28 '16 at 15:37
0

If your tuples contain str objects:

list(map(''.join, zip('abc', '123')))
# Returns ['a1', 'b2', 'c3']
jeromej
  • 10,508
  • 2
  • 43
  • 62