user1737647
user1737647

Reputation:

Elegant way to perform tuple arithmetic

What is the most elegant and concise way (without creating my own class with operator overloading) to perform tuple arithmetic in Python 2.7?

Lets say I have two tuples:

a = (10, 10)
b = (4, 4)

My intended result is

c = a - b = (6, 6)

I currently use:

c = (a[0] - b[0], a[1] - b[1])

I also tried:

c = tuple([(i - j) for i in a for j in b])

but the result was (6, 6, 6, 6). I believe the above works as a nested for loops resulting in 4 iterations and 4 values in the result.

Upvotes: 81

Views: 92766

Answers (8)

user5650823
user5650823

Reputation:

As an addition to Kohei Kawasaki's answer, for speed, the original solution was actually the fastest (For a length two tuple at least).

>>> timeit.timeit('tuple(map(add, a, b))',number=1000000,setup='from operator import add; a=(10,11); b=(1,2)')
0.6502681339999867
>>> timeit.timeit('(a[0] - b[0], a[1] - b[1])',number=1000000,setup='from operator import add; a=(10,11); b=(1,2)')
0.19015854899998885
>>> 

Upvotes: 3

Rustam A.
Rustam A.

Reputation: 879

Since in your question there only examples of 2-number-tuples, for such coordinate-like tuples, you may be good with simple built-in "complex" class:

>>> a=complex(7,5)
>>> b=complex(1,2)
>>> a-b
>>> c=a-b
>>> c
(6+3j)
>>> c.real
6.0
>>> c.imag
3.0

Upvotes: 2

Kohei Kawasaki
Kohei Kawasaki

Reputation: 141

JFYI, execution time in my laptop in 100000 times iteration

np.subtract(a, b) : 0.18578505516052246

tuple(x - y for x, y in zip(a, b)) : 0.09348797798156738

tuple(map(lambda x, y: x - y, a, b)) : 0.07900381088256836

from operator import sub tuple(map(sub, a, b)) : 0.044342041015625

operator looks more elegant for me.

Upvotes: 14

internety
internety

Reputation: 374

my element-wise tuple arithmetic helper

supported operations: +, -, /, *, d

operation = 'd' calculates distance between two points on a 2D coordinate plane

def tuplengine(tuple1, tuple2, operation):
    """ 
    quick and dirty, element-wise, tuple arithmetic helper,
    created on Sun May 28 07:06:16 2017
    ...
    tuple1, tuple2: [named]tuples, both same length
    operation: '+', '-', '/', '*', 'd'
    operation 'd' returns distance between two points on a 2D coordinate plane (absolute value of the subtraction of pairs)
    """
    assert len(tuple1) == len(tuple2), "tuple sizes doesn't match, tuple1: {}, tuple2: {}".format(len(tuple1), len(tuple2))
    assert isinstance(tuple1, tuple) or tuple in type(tuple1).__bases__, "tuple1: not a [named]tuple"
    assert isinstance(tuple2, tuple) or tuple in type(tuple2).__bases__, "tuple2: not a [named]tuple"
    assert operation in list("+-/*d"), "operation has to be one of ['+','-','/','*','d']"
    return eval("tuple( a{}b for a, b in zip( tuple1, tuple2 ))".format(operation)) \
    if not operation == "d" \
      else eval("tuple( abs(a-b) for a, b in zip( tuple1, tuple2 ))")

Upvotes: 1

miigotu
miigotu

Reputation: 1735

This can also be done just as nicely without an import at all, although lambda is often undesirable:

tuple(map(lambda x, y: x - y, a, b))

If you are looking to get the distance between two points on say a 2d coordinate plane you should use the absolute value of the subtraction of the pairs.

tuple(map(lambda x ,y: abs(x - y), a, b))

Upvotes: 7

Ashwini Chaudhary
Ashwini Chaudhary

Reputation: 251166

Use zip and a generator expression:

c = tuple(x-y for x, y in zip(a, b))

Demo:

>>> a = (10, 10)
>>> b = (4, 4)
>>> c = tuple(x-y for x, y in zip(a, b))
>>> c
(6, 6)

Use itertools.izip for a memory efficient solution.

help on zip:

>>> print zip.__doc__
zip(seq1 [, seq2 [...]]) -> [(seq1[0], seq2[0] ...), (...)]

Return a list of tuples, where each tuple contains the i-th element
from each of the argument sequences.  The returned list is truncated
in length to the length of the shortest argument sequence.

Upvotes: 37

vroomfondel
vroomfondel

Reputation: 3106

If you're looking for fast, you can use numpy:

>>> import numpy
>>> numpy.subtract((10, 10), (4, 4))
array([6, 6])

and if you want to keep it in a tuple:

>>> tuple(numpy.subtract((10, 10), (4, 4)))
(6, 6)

Upvotes: 91

Jared
Jared

Reputation: 26437

One option would be,

>>> from operator import sub
>>> c = tuple(map(sub, a, b))
>>> c
(6, 6)

And itertools.imap can serve as a replacement for map.

Of course you can also use other functions from operator to add, mul, div, etc.

But I would seriously consider moving into another data structure since I don't think this type of problem is fit for tuples

Upvotes: 49

Related Questions