Reputation:
First of all, I ask this question by pure curiosity to see some great one-liners skills. The sum()
function remains the best function to sum objects in a list.
But as said, I ask by pure curiosity: Is there a way to sum objects from a list
(obviously, without using sum()
) in one line? Let's say the list would be range(0, 100)
I have absolutely no idea how this could be achieved, but as Python is really great and flexible, so I have no doubt it is possible.
Upvotes: 2
Views: 5216
Reputation: 152810
Python may not be the best language for recursive approaches because (1) it doesn't support tail-recursion (2) function calls are really expensive (3) the recursion limit prevents deep recursions and (4) slicing sequences scales with O(n)
(where n
is the number of elements in the slice).
However you can use them for one-liners!
One approach would be just to successivly pop and add the first element until the sequence is exhausted:
>>> sum_func = lambda x: x[0] + sum_func(x[1:]) if x else 0
>>> sum_func(range(100))
4950
The first part is triggered as long as if x
(that is to say x
is not empty). This approach shows all the shortcomings of using recusion in Python: It hits the recursion limit for sequences of length ~300, it scales with O(n**2)
and it's really slow compared to the built-in sum
and reduce
approach.
One can mitigate one of the disadvantages by using a divide-and-conquer recursion approach:
>>> sum_func = lambda x: sum_func(x[:len(x)//2]) + sum_func(x[len(x)//2:]) if len(x) > 1 else x[0]
>>> sum_func(range(100))
4950
This time it recurses on both halfs of the list, thereby reducing the recusion depth from n
to log2(n)
, so it can handle even longer sequences. However it's not faster than the one above.
And of course there's always the cheat option:
>>> from numpy import sum
>>> sum(range(100))
4950
In case you really want it really fast :-)
Upvotes: 1
Reputation: 76254
Just for fun, here's a solution that needs no no built-in functions at all. It's basically a reimplentation of reduce
, using a bit of lambda magic.
>>>>(lambda f: lambda *args: f(f, *args))(lambda self, f, seq, d: d if not seq else f(seq[0], self(self, f, seq[1:], d)))(lambda a,b: a+b, range(100), 0)
4950
Upvotes: 1
Reputation: 122154
You can take a functional approach, using reduce
and an addition function (e.g. a lamdba
expression or operator.add
):
>>> from operator import add
>>> reduce(add, range(0, 100))
4950
(Note that in 3.x you need to from functools import reduce
first.)
Per the documentation, reduce(function, iterable)
will
Apply
function
of two arguments cumulatively to the items ofiterable
, from left to right, so as to reduce theiterable
to a single value.
Upvotes: 5