# How do I designate arguments in a nested map?

Say I have two lists,

list1 = {a, b, c}
list2 = {x, y, z}


and I want to map a function f over them to produce

{f[a,x], f[a,y], f[a,z], f[b,x], f[b,y], f[b,z], f[c,x], f[c,y], f[c,d]}


I would assume I map the function over the first list to produce a "list of functions", which then run over the 2nd list, something like:

Map[Map[f[#1, #2]&,list1]&, list2]


but I can't figure out how to leave #2 "empty" until the 2nd map kicks in. How can I separate them to generate all combinations of arguments?

-
I can't figure out how to leave #2 "empty": You might be able to get away with FunctionMap[Function[x, Map[f[#1, x] &, list1]], list2] — although I'd use Outer myself. –  rm -rf Nov 30 '12 at 22:29

What you try to achieve here is called Currying which can be used in other languages like Haskell naturally. In Mathematica this does not work like that.

Outer[f, list1, list2]
(*
{{f[a, x], f[a, y], f[a, z]},
{f[b, x], f[b, y], f[b, z]},
{f[c, x], f[c, y], f[c, z]}}
*)


or Flatten@Outer[f, list1, list2] if you want a flat list?

Of course this did not answer your question. Therefore, the real answer is: you can separate the Slots by using Function explicitely:

Map[Function[p2, Map[Function[p1, f[p1, p2]], list1]], list2]
(*
{{f[a, x], f[b, x], f[c, x]},
{f[a, y], f[b, y], f[c, y]},
{f[a, z], f[b, z], f[c, z]}}
*)


Here, it is clear that the p1 parameter is for the inner Function, while p2 is for the outer one. But note, that for your ordering, you need to do switch parameters.

-
Perfect! Learned a lot, and solved the problem! Thank you very much! –  Connor Glosser Nov 30 '12 at 22:39

Distribute is also handy.

Assuming f is not Listable:

In[39]:= Distribute[f[{a, b, c}, {x, y, z}], List]

Out[39]= {f[a, x], f[a, y], f[a, z], f[b, x], f[b, y], f[b, z],
f[c, x], f[c, y], f[c, z]}

-
This outputs {{f[a, x], f[b, y], f[c, z]}}. Apply[f,Distribute[{{a, b, c}, {x, y, z}}, List],1] gives the result above –  tchronis Dec 4 '13 at 14:34
I do get the right result with the input Distribute[f[{a, b, c}, {x, y, z}], List] –  MinHsuan Peng Dec 4 '13 at 22:04
Yes you are right, probably I had earlier applied some rules that affected the result. I cannot reproduce them - I will try on my other machine also tomorrow. Sorry for the inconvenience. –  tchronis Dec 4 '13 at 22:09
Not at all. But interesting, I wonder what setting would give you that result. –  MinHsuan Peng Dec 4 '13 at 22:15
I found the usual suspect. I had set f's Attributes to Listable. So maybe this should be noticed... –  tchronis Dec 4 '13 at 22:32
show 1 more comment

Or you could use Tuples, which appears a bit more natural to me.

Tuples[{{a, b, c}, {x, y, z}}]


creates

{{a, x}, {a, y}, {a, z}, {b, x}, {b, y}, {b, z}, {c, x}, {c, y}, {c, z}}


Afterwards Apply can be used to apply your function to the sublist

Apply[f , Tuples[{{a, b, c}, {x, y, z}}], {1}]


creates:

{f[a, x], f[a, y], f[a, z], f[b, x], f[b, y], f[b, z], f[c, x], f[c, y], f[c, z]}


create some random data:

list1 = RandomReal[1, 10^3];
list2 = RandomReal[1, 10^3];


Usage of a pure function to summarize the arguments (#1 + #2) &

 Apply[(#1 + #2) &, Tuples[{list1, list2}], {1}]; // AbsoluteTiming


yields {0.944316, Null}

Outer[(#1 + #2) &, list1, list2]; // AbsoluteTiming


yields {0.506706, Null}

-
I didn't know about tuples, but I had come to the same sort of solution (lists as arguments) using shifts and transposes. Apply[f, <list things>, 1] worked great to turn the lists into actual arguments. Thanks! –  Connor Glosser Nov 30 '12 at 22:39
Apply (@@@) would be a better choice here than Map –  Mike Honeychurch Nov 30 '12 at 22:41
Of course Mike is right: Apply is what you were looking for. I missed to notice that you explicitly not wanted to end up with a list of variables as input argument. –  Sascha Nov 30 '12 at 22:47