Search code examples
pythonpython-3.xreducepython-itertoolsfunctools

How to get all intermediary values of `reduce` in addition to the final result?


A call to functools.reduce returns only the final result:

>>> from functools import reduce
>>> a = [1, 2, 3, 4, 5]
>>> f = lambda x, y: x + y
>>> reduce(f, a)
15

Instead of writing a loop myself, does a function exist which returns the intermediary values, too?

[3, 6, 10, 15]

(This is only a simple example, I'm not trying to calculate the cumulative sum - the solution should work for arbitrary a and f.)


Solution

  • You can use itertools.accumulate():

    >>> from itertools import accumulate
    >>> list(accumulate([1, 2, 3, 4, 5], lambda x, y: x+y))[1:]
    [3, 6, 10, 15]
    

    Note that the order of parameters is switched relative to functools.reduce().

    Also, the default func (the second parameter) is a sum (like operator.add), so in your case, it's technically optional:

    >>> list(accumulate([1, 2, 3, 4, 5]))[1:]  # default func: sum
    [3, 6, 10, 15]
    

    And finally, it's worth noting that accumulate() will include the first term in the sequence, hence why the result is indexed from [1:] above.


    In your edit, you noted that...

    This is only a simple example, I'm not trying to calculate the cumulative sum - the solution should work for arbitrary a and f.

    The nice thing about accumulate() is that it is flexible about the callable it will take. It only demands a callable that is a function of two parameters.

    For instance, builtin max() satisfies that:

    >>> list(accumulate([1, 10, 4, 2, 17], max))
    [1, 10, 10, 10, 17]
    

    This is a longer form of using the unnecessary lambda:

    >>> # Don't do this
    >>> list(accumulate([1, 10, 4, 2, 17], lambda x, y: max(x, y)))
    [1, 10, 10, 10, 17]