Take the 2-minute tour ×
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
2  
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
add comment

3 Answers 3

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! –  Connor Glosser Nov 30 '12 at 22:39
add comment

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

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! –  Connor Glosser 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
add comment

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.