4

I have a list of functions: listFunc=[g1, g2, g3]. This list is generated with the code below:

def g(y): 
    def f(x):
        return x+y;
    return f; 
listFunc=list(map(g, [1, 2, 3])); 

Now, I have a list of arguments ListArg = [4, 5, 6];

How could I get a result list of [g1(4), g1(5), g1(6), g2(4), g2(5), g2(6), g3(4), g3(5), g3(6)] using map only?

I thought about using the following code:

map(lambda x:x(y), listFunc, ListArg)

But it only gives a result of [g1(4), g2(5), g3(6)].

Thanks,

Phrogz
  • 296,393
  • 112
  • 651
  • 745
  • For future reference, what you want is called the "Cartesian Product". For some (non-python) discussion see http://phrogz.net/lazy-cartesian-product – Phrogz Oct 29 '16 at 03:49

4 Answers4

5

If you want to use map(), you could do:

>>> [k for item in map(lambda x: [g(x) for g in listFunc], ListArg) for k in item]
[5, 6, 7, 6, 7, 8, 7, 8, 9]
Simeon Visser
  • 118,920
  • 18
  • 185
  • 180
  • Your `listFunc` and `ListArg` are swapped. Your code computes `g1(4), g2(4), ...` when `g1(4), g1(5), ...` was originally desired. :-) –  Oct 29 '16 at 02:45
5

This is a perfect use-case for a list comprehension with two for-clauses:

>>> def g1(x): return 1*x
... 
>>> def g2(x): return 2*x
... 
>>> def g3(x): return 3*x
... 
>>> funcs = [g1,g2,g3]
>>> args = [4,5,6]
>>> [f(a) for f in funcs for a in args]
[4, 5, 6, 8, 10, 12, 12, 15, 18]
>>> 

This is eminently readable and eminently functional - list comprehensions were borrowed from Haskell.

If you feel some deep need to use map, then you will have to approach it like this:

>>> import itertools
>>> list(map(lambda f,a : f(a), *zip(*itertools.product(funcs,args))))
[4, 5, 6, 8, 10, 12, 12, 15, 18]

Which is eminently unreadable and likely slower. List comprehensions win here.

juanpa.arrivillaga
  • 88,713
  • 10
  • 131
  • 172
  • 1
    Somehow, I kept reading into the question that the OP knew about list comprehensions, but wanted to use `map` anyway. – chepner Oct 29 '16 at 12:41
3

You can't quite do this with just map, but you can nest one call in another, and use sum to flatten the result.

>>> sum(map(lambda x : map(lambda f: f(x), ListArg),listFunc), [])
[5, 6, 7, 6, 7, 8, 7, 8, 9]
chepner
  • 497,756
  • 71
  • 530
  • 681
  • +1 because I love this answer. However, your maps are backward; the desired output is g1(4), g1(5), g1(6), g2(4), g2(5), ..., but your code executes g1(4), g2(4), g3(4), g1(5), g2(5), ... –  Oct 29 '16 at 02:39
  • Ah, tricky because `+` is commutative :) Just needed to swap the two lists. – chepner Oct 29 '16 at 12:29
3

itertools.product helps

def g(y): 
    def f(x):
        return x+y
    return f
funcs = map(g, [1, 2, 3])
args = [4,5,6]
p = itertools.product(funcs, args)
r = [f(arg) for f, arg in p]

The only alternative to the list comprehension I could come up with is:

def foo(args):
    f, a = args
    return f(a)
r = list(map(foo, p)) # using p from above
wwii
  • 23,232
  • 7
  • 37
  • 77
  • Never mind, i somehow saw something that wasn't there. I'm going to delete my comments for clarity. You may wish to do the same. – Phrogz Oct 29 '16 at 13:48