# Mapping functions over multiple lists

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

-

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

Flatten[Transpose[Outer[List, l1, l2, l3], {3, 2, 1}], 1] // Timing // First

0.297

0.764

-
Nice use of zero Part index. – Mike Honeychurch Jan 31 '14 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 '14 at 2:52
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 '14 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 '14 at 7:34
l1 = {a, b, c, d};
l2 = {x, y, z};
l3 = {u, v};
fun = {f, g, h, i};

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

-
Nuts, you beat me! I think mine may perform better though. Testing to follow... – Mr.Wizard Jan 31 '14 at 16:00
It does appear that my method is at least somewhat faster, but yours is good too. +1 – Mr.Wizard Jan 31 '14 at 16:04
Mr W does appear to be slightly faster. 0.000054 vs 0.000087 for the other solution. – Pam Jan 31 '14 at 16:10
@Mr.Wizard Once in a millenium I have that luck :) Nice touch Setting the heads! – István Zachar Jan 31 '14 at 18:09