2
$\begingroup$

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]}}    
$\endgroup$

2 Answers 2

8
$\begingroup$
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
$\endgroup$
4
  • $\begingroup$ Nice use of zero Part index. $\endgroup$ Jan 31, 2014 at 21:59
  • $\begingroup$ @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. $\endgroup$
    – Mr.Wizard
    Feb 1, 2014 at 2:52
  • 1
    $\begingroup$ 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) $\endgroup$ Feb 1, 2014 at 3:10
  • $\begingroup$ @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. $\endgroup$
    – Mr.Wizard
    Feb 1, 2014 at 7:34
3
$\begingroup$
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]}}
$\endgroup$
4
  • 1
    $\begingroup$ Nuts, you beat me! I think mine may perform better though. Testing to follow... $\endgroup$
    – Mr.Wizard
    Jan 31, 2014 at 16:00
  • $\begingroup$ It does appear that my method is at least somewhat faster, but yours is good too. +1 $\endgroup$
    – Mr.Wizard
    Jan 31, 2014 at 16:04
  • $\begingroup$ Mr W does appear to be slightly faster. 0.000054 vs 0.000087 for the other solution. $\endgroup$
    – Pam
    Jan 31, 2014 at 16:10
  • $\begingroup$ @Mr.Wizard Once in a millenium I have that luck :) Nice touch Setting the heads! $\endgroup$ Jan 31, 2014 at 18:09

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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