Search code examples
pythondictionaryzipreduceiterable-unpacking

map of function list and arguments: unpacking difficulty


I have an assignment in a mooc where I have to code a function that returns the cumulative sum, cumulative product, max and min of an input list.
This part of the course was about functional programming, so I wanted to go all out on this, even though I can use other ways.
So I tried this:

from operator import mul
from itertools import repeat
from functools import reduce
def reduce2(l):
    print(l)
    return reduce(*l)
def numbers(l):
    return tuple(map(reduce2, zip([sum, mul,min, max], repeat(l,4))))
l=[1,2,3,4,5]
numbers(l)

My problem is that it doesn't work. zip will pass only one object to reduce if I use it inside map, and unpacking the zip will yield the 4 tuple of (function and argument list l) so I defined reduce2 for this reason, I wanted to unpack the zip inside it but it did not work.
Python returns a TypeError: int' object is not iterable
I thought that I could use return reduce(l[0],l[1]) in reduce2, but there is still the same Error.
I don't understand the behavior of python here. If I merely use return reduce(l), it returns again a TypeError: reduce expected at least 2 arguments, got 1

What's happening here? How could I make it work? Thanks for your help.


Solution

  • Effectively, you are trying to execute code like this:

    xs = [1, 2, 3, 4, 5]
    reduce(sum, xs)
    

    But sum takes an iterable and isn't really compatible with direct use via reduce. Instead, you need a function that takes 2 arguments and returns their sum -- a function analogous to mul. You can get that from operator:

    from operator import mul, add
    

    Then just change sum to add in your program.

    BTW, functional programming has a variable naming convention that is really cool: x for one thing, and xs for a list of them. It's much better than the hard-to-read l variable name. Also it uses singular/plural to tell you whether you are dealing with a scalar value or a collection.