Apply MapThread to all but one variable

I would like to know what is the most efficient to implement the following computation. Given three lists

    a = {a_1,a_2, a_3, …, a_n}
b = {b_1,b_2, b_3, …, b_n}
c = {c_1,c_2, c_3, …, c_n}


and a function $$f(x_1,x_2,x_3)$$, obtain

     f(a_1,b_1,c_1)   f(a_1,b_1,c_2)   .....   f(a_1,b_1,c_n)
f(a_2,b_2,c_1)   f(a_2,b_2,c_2)   .....   f(a_2,b_2,c_n)
.....            .....            .....   .....
f(a_n,b_n,c_1)   f(a_n,b_n,c_2)   .....   f(a_n,b_n,c_n)


I cannot find a solution not using For.

Another possibility is to use the 3-arg version of Thread. With Sjoerd's example:

n = 3;
l1 = Array[a,n];
l2 = Array[b,n];
l3 = Array[c,n];


Using Thread:

Thread /@ Thread[f[l1, l2, l3], List, 2]


{{f[a[1], b[1], c[1]], f[a[1], b[1], c[2]], f[a[1], b[1], c[3]]}, {f[a[2], b[2], c[1]], f[a[2], b[2], c[2]], f[a[2], b[2], c[3]]}, {f[a[3], b[3], c[1]], f[a[3], b[3], c[2]], f[a[3], b[3], c[3]]}}

• Super-fast and very elegant, but does not work if f is already defined to generate a result. In this case you'll need something like Thread /@ Thread[Inactive[f][l1, l2, l3], List, 2] // Activate. – Roman Apr 27 '19 at 7:13

Here's one way to do it with Outer:

n = 3;
l1 = Array[a, n];
l2 = Array[b, n];
l3 = Array[c, n];

Outer[
f[#1[[1]], #1[[2]], #2] &,
Transpose @ {l1, l2},
l3,
1
]


Out[25]= {{f[a[1], b[1], c[1]], f[a[1], b[1], c[2]], f[a[1], b[1], c[3]]}, {f[a[2], b[2], c[1]], f[a[2], b[2], c[2]], f[a[2], b[2], c[3]]}, {f[a[3], b[3], c[1]], f[a[3], b[3], c[2]], f[a[3], b[3], c[3]]}}

• Or Outer[f[Sequence @@ #1, #2] &, Transpose@{l1, l2}, l3, 1] so you don't need to unravel #1 manually. – Roman Apr 26 '19 at 22:01
a = {a1, a2, a3, a4, a5};
b = {b1, b2, b3, b4, b5};
c = {c1, c2, c3, c4, c5};

Table[f[a[[j]], b[[j]], c[[k]]], {j, 1, 5}, {k, 1, 5}]


Another way with Curry and Through.

Through /@ Apply[Curry[f, {2, 3, 1}] /@ c] /@ Transpose@{a, b}


Hope this helps.