2

The initializer comes after the iterable. This causes problems for partial application. Consider these (trivial) examples:

In [1]: from functools import reduce, partial

In [2]: f = partial(reduce, lambda a,b: a+b, 100)

In [3]: f([1,2,3])
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-3-816cce84b257> in <module>()
----> 1 f([1,2,3])

TypeError: reduce() arg 2 must support iteration

In [4]: f = partial(reduce, lambda a,b: a+b, initializer=100)

In [5]: f([1,2,3])
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-5-816cce84b257> in <module>()
----> 1 f([1,2,3])

TypeError: reduce() takes no keyword arguments

Is there some trick to get around this?

Solomon Bothwell
  • 1,004
  • 2
  • 12
  • 21

2 Answers2

1

Just change the order of arguments:

>>> f = partial(lambda func, init, iterable: reduce(func, iterable, init), 
                lambda a,b: a+b, 100)
>>> f([1,2,3])
106
Marat
  • 15,215
  • 2
  • 39
  • 48
0

Marat gave a great solution. For fun, I wrote foldl with the arguments flipped. I'm curious how this would compare performance-wise to using a lambda to flip the arguments like Marat did.

def foldl(f: Callable, acc: Any, xs: Iterable) -> Any:
    if not xs:
        return acc
    return foldl(f, f(acc, xs[0]), xs[1:]) 
Solomon Bothwell
  • 1,004
  • 2
  • 12
  • 21