A coworker came to me with a simple python problem and asked if I could find a better solution. The problem is as follows.
Given a list of 2 element tuples (suchas x and y coordinates), how do I sum the tuples so that they only sum the respective elements (sum(x), sum(y)).
[(1,2), (3,4), (5,6), (7,8)] => (16, 20)
For the following solutions, we will give that
tuple_list = [(1,2), (3,4), (5,6), (7,8)]
and for performance testing:
long_tuple_list = [[(1,2), (3,4), ..., (999, 1000)]]
All code and tests will be run in python 3.6.
So the Python101 type solution would look a little something like this:
Our results from
%timeit with jupyter notebook as as follows:
> %timeit sum_tuples(long_tuple_list)
The solution my coworker came up with went something like
This is pretty nice, its a one liner that makes good use of builtin
zip and uses,
sum. This performs nicely due to the list comprehension:
However there is an unnecessary list casting in here since we want to return a tuple, so we can refactor this to:
Remove the square brackets to cast directly to tuple results in the same speed but saves us two characters and an operation.
After falling in love with functional programming, my first gut reaction to this
was to use
This is probably my favorite. One liner, all builtin keyword methods. It replaces
the comprehension with
map and performs a hair faster too:
In functional programming, this type of problem where you go from many to one is
often handled with a reducer. Since python3,
reduce is no longer a builtin keyword,
but it is still available via
The initial reduce with a lambda looks like:
from functools import reduce
So to me, this looks weird. I don’t like the
lambda anonymous function, we are
map anyways inside, and the whole thing is a bit hard to read. Also
due to the anonymous
lambda, the thing is slow:
But lets not count reduce dead yet, we can clean up that anonymous function with a named one:
from functools import reduce
This to me looks like the best functional approach as far as signal to noise. It
defines a function on how to add two tuples together, then uses
reduce to reduce
the list to a single result. The code reads exactly as it does. However since
reduce is no longer first class, it’s performance is pretty similar to the above
To be complete, we could use numpy to do matrix addition to get our answer. *Note,
numpy is huge. According to pypi, its between 4MB and 12MB depending on your
operating system. This is the equvalent of killing a fly with a sledge hammer.
from numpy import array
arrays do matrix math, so adding them will result the behavior that we want.
However, the cast to
array comes with a cost:
Again for completeness, we can look at an OOP solution to this problem.
So here we cast all of our tuples to a new class,
Mtuple, which defines a
function. This allows us to override the behavior of
sum on these objects.
We then can simply
sum the list of
Mtuple, given we give
sum a starting value of
Mtuple((0,0))). However we run into the same problem with casting as we did with
While I like how clean
reduce looks, due to it no longer being “pythonic”, I would
have to say the best way to solve this problem is either using a comprension or
map. Personally I think
map(sum, zip(*tuple_list)) is the best because
it is lazily evaluated and can be further composed.