Tell me more ×
Mathematica Stack Exchange is a question and answer site for users of Mathematica. It's 100% free, no registration required.

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?

share|improve this question
1  
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

3 Answers

up vote 8 down vote accepted

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.

But what about

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.

share|improve this answer
Perfect! Learned a lot, and solved the problem! Thank you very much! – ConnorG Nov 30 '12 at 22:39

Distribute is also handy.

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]}
share|improve this answer

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]}

Addition: comparison of speed:

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}


share|improve this answer
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! – ConnorG Nov 30 '12 at 22:39
1  
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

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.