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.

I am not sure if this is a duplicate. Spent some time looking over list-manip questions.

I’d like to know the Quickest Way to achieve the following Mapping of a function over multiple lists.

Suppose we have multiple lists of unequal length:

l1 = {a, b, c, d};
l2 = {x, y, z};
l3 = {u, v};

Q1 What is the quickest way to generate another list as follows (where f is a function):

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

Now suppose you have a list of functions:

{f,g,h,i}

Q2 What is the quickest way to generate a list as follows:

{{f[a, x, u], g[b, x, u], h[c, x, u], i[d, x, u]},
{f[a, y, u], g[b, y, u], h[c, y, u], i[d, y, u]},
...
{f[a, z, v], g[b, z, v], h[c, z, v], i[d, z, v]}}    
share|improve this question
add comment

2 Answers

up vote 6 down vote accepted
l1 = {a, b, c, d};
l2 = {x, y, z};
l3 = {u, v};
fns = {f, g, h, i};

expr = Outer[f, l1, l2, l3] ~Flatten~ {3, 2}
{{f[a, x, u], f[b, x, u], f[c, x, u], f[d, x, u]},
 {f[a, y, u], f[b, y, u], f[c, y, u], f[d, y, u]},
 {f[a, z, u], f[b, z, u], f[c, z, u], f[d, z, u]},
 {f[a, x, v], f[b, x, v], f[c, x, v], f[d, x, v]},
 {f[a, y, v], f[b, y, v], f[c, y, v], f[d, y, v]},
 {f[a, z, v], f[b, z, v], f[c, z, v], f[d, z, v]}}
expr[[All, All, 0]] = fns;
expr
{{f[a, x, u], g[b, x, u], h[c, x, u], i[d, x, u]},
 {f[a, y, u], g[b, y, u], h[c, y, u], i[d, y, u]},
 {f[a, z, u], g[b, z, u], h[c, z, u], i[d, z, u]},
 {f[a, x, v], g[b, x, v], h[c, x, v], i[d, x, v]},
 {f[a, y, v], g[b, y, v], h[c, y, v], i[d, y, v]},
 {f[a, z, v], g[b, z, v], h[c, z, v], i[d, z, v]}}

For creation of the second array directly, without creating the first, use List in place of f in Outer for best performance.

A single performance comparison with István's code, for the second array only:

l1 = RandomInteger[999, 150];
l2 = RandomInteger[999, 100];
l3 = RandomInteger[999, 70];
fns = Array[a, 150];

(expr = Outer[List, l1, l2, l3] ~Flatten~ {3, 2}; expr[[All, All, 0]] = fns; 
   expr) // Timing // First

MapThread[Apply, {fns, #}] & /@ 
   Flatten[Transpose[Outer[List, l1, l2, l3], {3, 2, 1}], 1] // Timing // First
0.297

0.764
share|improve this answer
    
Nice use of zero Part index. –  Mike Honeychurch Jan 31 at 21:59
    
@MikeHoneychurch Thanks. Are you the one who introduced that here? Sadly I cannot remember and I couldn't find the original but I wanted to give credit. –  Mr.Wizard Feb 1 at 2:52
1  
I have no idea if I was the first. I know in early days here I noted that you could change Head that way rather than use Apply. Didn't mention this looking for credit -- just thought it was a good use of the zero index (I tend to typically go to Part before other functions) –  Mike Honeychurch Feb 1 at 3:10
    
@Mike Then yes, I think you were the one I learned it from. I know you weren't seeking credit but I can give it nevertheless. :-) (If you can recall or find that first post let me know.) I understand that it is nice to see people using a method that one proposed. –  Mr.Wizard Feb 1 at 7:34
add comment
l1 = {a, b, c, d};
l2 = {x, y, z};
l3 = {u, v};
fun = {f, g, h, i};

MapThread[Apply, {fun, #}] & /@
   Flatten[Transpose[Outer[List, l1, l2, l3], {3, 2, 1}], 1]
{{f[a, x, u], g[b, x, u], h[c, x, u], i[d, x, u]},
 {f[a, y, u], g[b, y, u], h[c, y, u], i[d, y, u]},
 {f[a, z, u], g[b, z, u], h[c, z, u], i[d, z, u]},
 {f[a, x, v], g[b, x, v], h[c, x, v], i[d, x, v]},
 {f[a, y, v], g[b, y, v], h[c, y, v], i[d, y, v]},
 {f[a, z, v], g[b, z, v], h[c, z, v], i[d, z, v]}}
share|improve this answer
1  
Nuts, you beat me! I think mine may perform better though. Testing to follow... –  Mr.Wizard Jan 31 at 16:00
    
It does appear that my method is at least somewhat faster, but yours is good too. +1 –  Mr.Wizard Jan 31 at 16:04
    
Mr W does appear to be slightly faster. 0.000054 vs 0.000087 for the other solution. –  Pam Jan 31 at 16:10
    
@Mr.Wizard Once in a millenium I have that luck :) Nice touch Setting the heads! –  István Zachar Jan 31 at 18:09
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.