151

Is there anyway to get tuple operations in Python to work like this:

>>> a = (1,2,3)
>>> b = (3,2,1)
>>> a + b
(4,4,4)

instead of:

>>> a = (1,2,3)
>>> b = (3,2,1)
>>> a + b
(1,2,3,3,2,1)

I know it works like that because the __add__ and __mul__ methods are defined to work like that. So the only way would be to redefine them?

15 Answers 15

176

Using all built-ins..

tuple(map(sum, zip(a, b)))
Sign up to request clarification or add additional context in comments.

4 Comments

This seems to be the simpler, superior answer. Why isn't it accepted?
it's good, but technically not what's asked for because map returns a list, not a tuple... so: tuple(map(sum,zip(a,b))
The syntax is mystic.
The benefit of this one is that you can extend it to: tuple(map(sum,zip(a,b, c))
164
import operator
tuple(map(operator.add, a, b))

8 Comments

I'd say this is the most pythonic solution.
Except that map() is semi-deprecated. See artima.com/weblogs/viewpost.jsp?thread=98196 for an article by Guido where it mentions how map is better written as a list comprehension.
It also blows up if a & b don't contain the same number of elements, or aren't "addable" (ex: map(operator.add, (1,2), ("3", "4"))
tuple([item1 + item2 for item1, item2 in zip(a, b)]) would be the equivalent as a list comprehension.
@AdamParkin, generator comprehensions are even better tuple(item1 + item2 for item1, item2 in zip(a, b)).
|
47

This solution doesn't require an import:

tuple(map(lambda x, y: x + y, tuple1, tuple2))

1 Comment

This solution is also faster than the other no-import, one-liner solution (map(sum, zip(a, b)))
23

Sort of combined the first two answers, with a tweak to ironfroggy's code so that it returns a tuple:

import operator

class stuple(tuple):
    def __add__(self, other):
        return self.__class__(map(operator.add, self, other))
        # obviously leaving out checking lengths

>>> a = stuple([1,2,3])
>>> b = stuple([3,2,1])
>>> a + b
(4, 4, 4)

Note: using self.__class__ instead of stuple to ease subclassing.

Comments

23
from numpy import array

a = array( [1,2,3] )
b = array( [3,2,1] )

print a + b

gives array([4,4,4]).

See http://www.scipy.org/Tentative_NumPy_Tutorial

1 Comment

This will work, but it's a bit heavy to import numpy just for a simple addition operation.
21

Generator comprehension could be used instead of map. Built-in map function is not obsolete but it's less readable for most people than list/generator/dict comprehension, so I'd recommend not to use map function in general.

tuple(p+q for p, q in zip(a, b))

Comments

6

simple solution without class definition that returns tuple

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

Comments

6

All generator solution. Not sure on performance (itertools is fast, though)

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

Comments

6

even simpler and without using map, you can do that

>>> tuple(sum(i) for i in zip((1, 2, 3), (3, 2, 1)))
(4, 4, 4)

Comments

3

Yes. But you can't redefine built-in types. You have to subclass them:

class MyTuple(tuple):
    def __add__(self, other):
         if len(self) != len(other):
             raise ValueError("tuple lengths don't match")
         return MyTuple(x + y for (x, y) in zip(self, other))

1 Comment

but then you can't use the tuple syntax.
3

I currently subclass the "tuple" class to overload +,- and *. I find it makes the code beautiful and writing the code easier.

class tupleN(tuple):
    def __add__(self, other):
        if len(self) != len(other):
             return NotImplemented
        else:
             return tupleN(x+y for x,y in zip(self,other))
    def __sub__(self, other):
        if len(self) != len(other):
             return NotImplemented
        else:
             return tupleN(x-y for x,y in zip(self,other))
    def __mul__(self, other):
        if len(self) != len(other):
             return NotImplemented
        else:
             return tupleN(x*y for x,y in zip(self,other))


t1 = tupleN((1,3,3))
t2 = tupleN((1,3,4))
print(t1 + t2, t1 - t2, t1 * t2, t1 + t1 - t1 - t1)
(2, 6, 7) (0, 0, -1) (1, 9, 12) (0, 0, 0)

Comments

0

Here is another handy solution if you are already using numpy. It is compact and the addition operation can be replaced by any numpy expression.

import numpy as np
tuple(np.array(a) + b)

Comments

0

I keep coming back to this question, and I don't particularly like any of the answers as they are all answering the question for the general case, and I'm normally looking for the answer to a special case: I'm normally using a fixed tuple count, e.g. for n-dimensions.

   # eg adding a dx/dy to an xy point.
   # if I have a point xy and another point dxdy
   x, y = xy
   dx, dy = dxdy
   return x+dx, y+dy

while I normally shudder at unnecessary variables, the reason why I am unpacking a tuple is normally because I am working on the elements as individuals, and that is what is happening with tuple addition as requested above.

Comments

0

minimal class for all common numeric binary and unary operators
what i would want by default from a tuple-like data structure in any language

from math import ceil,floor,trunc
from operator import (add,and_,eq,floordiv,ge,gt,invert,le,lshift,lt,mod,mul,ne,
  neg,or_,pos,rshift,sub,truediv,xor,)
from itertools import repeat
from typing import Iterable
class ntuple(tuple):
  def __lt__(a,b): return ntuple(map(lt,a,a._b(b)))
  def __le__(a,b): return ntuple(map(le,a,a._b(b)))
  def __eq__(a,b): return ntuple(map(eq,a,a._b(b)))
  def __ne__(a,b): return ntuple(map(ne,a,a._b(b)))
  def __gt__(a,b): return ntuple(map(gt,a,a._b(b)))
  def __ge__(a,b): return ntuple(map(ge,a,a._b(b)))
  def __add__(a,b): return ntuple(map(add,a,a._b(b)))
  def __sub__(a,b): return ntuple(map(sub,a,a._b(b)))
  def __mul__(a,b): return ntuple(map(mul,a,a._b(b)))
  def __matmul__(a,b): return sum(map(mul,a,a._b(b)))
  def __truediv__(a,b): return ntuple(map(truediv,a,a._b(b)))
  def __floordiv__(a,b): return ntuple(map(floordiv,a,a._b(b)))
  def __mod__(a,b): return ntuple(map(mod,a,a._b(b)))
  def __divmod__(a,b): return ntuple(map(divmod,a,a._b(b)))
  def __pow__(a,b,m=None): return ntuple(pow(a,b,m) for a,b in zip(a,a._b(b)))
  def __lshift__(a,b): return ntuple(map(lshift,a,a._b(b)))
  def __rshift__(a,b): return ntuple(map(rshift,a,a._b(b)))
  def __and__(a,b): return ntuple(map(and_,a,a._b(b)))
  def __xor__(a,b): return ntuple(map(xor,a,a._b(b)))
  def __or__(a,b): return ntuple(map(or_,a,a._b(b)))
  def __neg__(a): return ntuple(map(neg,a))
  def __pos__(a): return ntuple(map(pos,a))
  def __abs__(a): return ntuple(map(abs,a))
  def __invert__(a): return ntuple(map(invert,a))
  def __round__(a,n=None): return ntuple(round(e,n) for e in a)
  def __trunc__(a): return ntuple(map(trunc,a))
  def __floor__(a): return ntuple(map(floor,a))
  def __ceil__(a): return ntuple(map(ceil,a))
  def _b(a,b): return b if isinstance(b,Iterable) else repeat(b,len(a))
ntuple((-1, 0, 2)) + (6, 4, 2) = (5, 4, 4)

ntuple((-1, 0, 2)) +  2 = (1, 2, 4)
ntuple((-1, 0, 2)) ** 2 = (1, 0, 4)
ntuple(( 1, 2, 3)) << 2 = (4, 8, 12)

-ntuple((-1, 0, 2)) = (1, 0, -2)

round(ntuple((-1.5, 0.6, 2.4))) = (-2, 1, 2)

sum(ntuple(a...)*(b...)) == ntuple(a...)@(b...)

Comments

-2

In case someone need to average a list of tuples:

import operator 
from functools import reduce
tuple(reduce(lambda x, y: tuple(map(operator.add, x, y)),list_of_tuples))

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.