Search code examples
pythonlistfunctional-programmingreducefold

What is the 'pythonic' equivalent to the 'fold' function from functional programming?


What is the most idiomatic way to achieve something like the following, in Haskell:

foldl (+) 0 [1,2,3,4,5]
--> 15

Or its equivalent in Ruby:

[1,2,3,4,5].inject(0) {|m,x| m + x}
#> 15

Obviously, Python provides the reduce function, which is an implementation of fold, exactly as above, however, I was told that the 'pythonic' way of programming was to avoid lambda terms and higher-order functions, preferring list-comprehensions where possible. Therefore, is there a preferred way of folding a list, or list-like structure in Python that isn't the reduce function, or is reduce the idiomatic way of achieving this?


Solution

  • Starting Python 3.8, and the introduction of assignment expressions (PEP 572) (:= operator), which gives the possibility to name the result of an expression, we can use a list comprehension to replicate what other languages call fold/foldleft/reduce operations:

    Given a list, a reducing function and an accumulator:

    items = [1, 2, 3, 4, 5]
    f = lambda acc, x: acc * x
    accumulator = 1
    

    we can fold items with f in order to obtain the resulting accumulation:

    [accumulator := f(accumulator, x) for x in items]
    # accumulator = 120
    

    or in a condensed formed:

    acc = 1; [acc := acc * x for x in [1, 2, 3, 4, 5]]
    # acc = 120
    

    Note that this is actually also a "scanleft" operation as the result of the list comprehension represents the state of the accumulation at each step:

    acc = 1
    scanned = [acc := acc * x for x in [1, 2, 3, 4, 5]]
    # scanned = [1, 2, 6, 24, 120]
    # acc = 120