2

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.

MSeifert
  • 145,886
  • 38
  • 333
  • 352

3 Answers3

5

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 of iterable, from left to right, so as to reduce the iterable to a single value.

jonrsharpe
  • 115,751
  • 26
  • 228
  • 437
  • Well, I didn't expected something so short, I'll let the thread open for some times to see some other proposals, even if this one is really KISS –  Sep 04 '14 at 16:53
  • 1
    @CarlierRobin how long a *"one-line... implementation"* were you expecting? – jonrsharpe Sep 04 '14 at 16:53
  • You can also replace `add` with `lambda x, y: x + y`, so that this does not even need imports in Python 2. – Oberon Sep 04 '14 at 16:55
  • @jonrsharpe To be honest I had in mind someone that one able to code big script in one instruction, just for fun. Obviously the script was enormous. So in my mind it was a long long thing. I didn't new there were a builtin function that does that and was thinking on how do this sum without thing like that. Even if this sol is great! –  Sep 04 '14 at 16:56
  • 2
    @CarlierRobin maybe you should look at https://codegolf.stackexchange.com. You know, just for fun. – kojiro Sep 04 '14 at 16:57
  • @kokiro It could indeed more be the place to aks this, you're right, I'll let this open and feel free to do a close vote on this one –  Sep 04 '14 at 16:58
  • It's not really code golf, as that aims to minimise length. I don't think SE has a site for needless complexity! – jonrsharpe Sep 04 '14 at 17:04
  • `reduce` is so good it's been removed from Python3. :-/ "batteries included except when we arbitrarily decide to remove useful batteries". – Eric Duminil Apr 23 '17 at 12:52
  • 1
    @EricDuminil just moved; as I say in the question you can still import it from within the standard library. https://docs.python.org/3/whatsnew/3.0.html#builtins – jonrsharpe Apr 23 '17 at 12:53
  • @jonrsharpe: Yes, but it's still doesn't explain why it's been moved in the first place. There are many other, less useful functions that are directly available without `import`. Why not remove `map` for example? You can use a comprehension instead, which is more readable. There's no other readable, short alternative to `reduce`. – Eric Duminil Apr 23 '17 at 12:54
  • Thanks for the link, but it doesn't change my opinion one bit. Basically, `reduce` has been moved because it's possible to write unclear code with it. With this reasoning, you could remove every function and operator from standard Python. – Eric Duminil Apr 23 '17 at 13:04
  • @EricDuminil I'm just trying to give you information, not attacking or defending the choice to move it; it's up to the BDFL. If you have a problem with it, I can only suggest you take it to the mailing list. – jonrsharpe Apr 23 '17 at 13:07
  • Sorry, that was nothing personal. I like your answer and upvoted it. When I don't agree with some Python designs (it doesn't happen too regularly), I look at JS code for 5 minutes and suddenly, Python looks much clearer and cleaner. My other whish for Python : a standard `flatten` function :) – Eric Duminil Apr 23 '17 at 13:10
1

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
Kevin
  • 74,910
  • 12
  • 133
  • 166
  • Wow, That was the kind of thing I was thinking. I'll need my time to understand that one! –  Sep 04 '14 at 16:59
1

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 :-)

Community
  • 1
  • 1
MSeifert
  • 145,886
  • 38
  • 333
  • 352
  • 2
    @EricDuminil yes, because slicing is `O(n)`. But that's not going to matter much because before that's significant the function hits the recursion limit. And the constant factor (repeatedly calling the function) is huge. – MSeifert Apr 23 '17 at 13:04