Python element-wise tuple operations like sum
Question:
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?
Answers:
import operator
tuple(map(operator.add, a, b))
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))
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.
Using all built-ins..
tuple(map(sum, zip(a, b)))
from numpy import array
a = array( [1,2,3] )
b = array( [3,2,1] )
print a + b
gives array([4,4,4])
.
simple solution without class definition that returns tuple
import operator
tuple(map(operator.add,a,b))
All generator solution. Not sure on performance (itertools is fast, though)
import itertools
tuple(x+y for x, y in itertools.izip(a,b))
This solution doesn’t require an import:
tuple(map(lambda x, y: x + y, tuple1, tuple2))
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))
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)
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))
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)
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)
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.
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?
import operator
tuple(map(operator.add, a, b))
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))
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.
Using all built-ins..
tuple(map(sum, zip(a, b)))
from numpy import array
a = array( [1,2,3] )
b = array( [3,2,1] )
print a + b
gives array([4,4,4])
.
simple solution without class definition that returns tuple
import operator
tuple(map(operator.add,a,b))
All generator solution. Not sure on performance (itertools is fast, though)
import itertools
tuple(x+y for x, y in itertools.izip(a,b))
This solution doesn’t require an import:
tuple(map(lambda x, y: x + y, tuple1, tuple2))
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))
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)
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))
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)
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)
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.