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.

Given two lists $l_a = \{a_1, a_2, a_3\}$, $l_b = \{b_1, b_2, b_3, b_4\}$ and some function $f$ accepting two arguments, how can I produce a list of all values $f(a, b)$ for $a\in l_a$ and $b \in l_b$ using functional construction?

share|improve this question
    
I would like to get {f[a1,b1],f[a1,b2],f[a1,b2],...,f[a3,b1],...,f[a3,b4]} (eg. all possible pairs) –  Jarek Miszczak Dec 21 '12 at 20:22
3  
Use Outer[f,la, lb] where la and lb are your lists –  rm -rf Dec 21 '12 at 20:22
    
OK - extra question just for fun. How would you implement Outer using functional style? –  Jarek Miszczak Dec 21 '12 at 20:32
    
@JarekMiszczak Something like f[#, k] & /@ {x1,x2}/. k -> # & /@ {y1, y2, y3}? –  belisarius Dec 21 '12 at 20:45
    
@belisarius Thanks for this anwser - I especially like the trick with /. k -> # & –  Jarek Miszczak Dec 21 '12 at 21:07
show 1 more comment

3 Answers

up vote 10 down vote accepted

You could do Outer[f, la, lb] as already suggested. Alternatively you could do

Partition[Apply[f, Tuples[{la, lb}], {1}], Length[la]]

or

Table[f[ai,bi],{ai,la},{bi,lb}]

or

Array[f[la[[#1]], lb[[#2]]] &, {Length[la], Length[lb]}]
share|improve this answer
1  
As for me the second option is great - I'm using list of matrices and I never thought about using them as iterators... –  Jarek Miszczak Dec 21 '12 at 20:52
    
@JarekMiszczak That's a great and often overlooked syntax salt –  belisarius Dec 21 '12 at 22:49
add comment

While Outer is the canonical function, in addition to the methods that Sasha shows you could use:

Distribute

lst1 = {1, 3, 5, 7};
lst2 = {2, 4, 6, 8};

Distribute[f[lst1, lst2], List]
{f[1, 2], f[1, 4], f[1, 6], f[1, 8], f[3, 2], f[3, 4], f[3, 6], 
 f[3, 8], f[5, 2], f[5, 4], f[5, 6], f[5, 8], f[7, 2], f[7, 4], 
 f[7, 6], f[7, 8]}

Through and Listable

SetAttributes[f, Listable]
f[a__][x_] := f[a, x]

f[lst1][lst2] // Through

Thread and Map

g[a__][x_List] := Thread @ g[a, #] & /@ x

g[lst1][lst2]

ReplaceList

In a comment Rojo suggested using ReplaceList which is quite elegant:

ReplaceList[{lst1, lst2}, {{___, a_, ___}, {___, b_, ___}} :> {a, b}]

Recursion

h[{a_, b__}, x___] := h[{b}, x] ~Prepend~ h[x, a]
h[{a_}, x___] := {h[x, a]}

h[lst1, lst2]

I rather like this last one. It works with multiple lists too:

h[{1, 2, 3}, {a, b}, {x, y}]
{{{h[1, a, x], h[1, a, y]}, {h[1, b, x], h[1, b, y]}},
 {{h[2, a, x], h[2, a, y]}, {h[2, b, x], h[2, b, y]}},
 {{h[3, a, x], h[3, a, y]}, {h[3, b, x], h[3, b, y]}}}

Formulated using linked lists for higher performance:

h[{a_, b__}, x___] := {h[x, a], h[{b}, x]}
h[{a_}, x___] := h[x, a]

h[{1, 2, 3}, {a, b}, {x, y}] // Flatten
{h[1, a, x], h[1, a, y], h[1, b, x], h[1, b, y],
 h[2, a, x], h[2, a, y], h[2, b, x], h[2, b, y],
 h[3, a, x], h[3, a, y], h[3, b, x], h[3, b, y]}
share|improve this answer
1  
If the intent doesn't imply nesting them, a nice one is also ReplaceList[{{1, 2, 3}, {a, b}}, {{___, a_, ___}, {___, b_, ___}} :> {a, b}] –  Rojo Dec 22 '12 at 15:40
    
@Rojo Similar to this answer which as you'll note I liked. May I include that in my answer? –  Mr.Wizard Dec 23 '12 at 3:11
    
Sure. By the way, was this useful? –  Rojo Dec 23 '12 at 6:22
    
@Rojo for some reason I'm not getting @notifications today. I looked at that answer briefly but I intended to return to it. In the context of a larger Grid layout I believe that different sections will not align. Sorry for not being responsive to your answer without prompting. –  Mr.Wizard Dec 23 '12 at 11:25
add comment

ListConvolve

 l1 = {a1, a2, a3}; l2 = {b1, b2, b3};
 Union @@ ListConvolve[l1, l2, 1, l2, f, List]
 (* {f[a1, b1], f[a1, b2], f[a1, b3], 
     f[a2, b1], f[a2, b2], f[a2, b3], 
     f[a3, b1], f[a3, b2], f[a3, b3]} *)

Tuples - an alternative usage

  Tuples[f[l1, l2]]
  (* {f[a1, b1], f[a1, b2], f[a1, b3], 
     f[a2, b1], f[a2, b2], f[a2, b3], 
     f[a3, b1], f[a3, b2], f[a3, b3]} *)

To partition the flat lists above, use Partition or the new-in-Version-9 ArrayReshape:

 ArrayReshape[%, {Length@l1, Length@l2}] 
 (* {{f[a1, b1], f[a1, b2], f[a1, b3]}, 
     {f[a1, b4], f[a2, b1], f[a2, b2]}, 
     {f[a2, b3], f[a2, b4], f[a3, b1]}}*)
share|improve this answer
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.