# Map-Thread-Through-Apply a list of functions onto a list of (lists of) values

I have a list of functions:

fns = {f, g, h}


and a list of triples:

list = {{1,2,3},{11,22,33},{111,222,333},{1111,2222,3333}};


What's the best way to apply f to the first element of every triple, g to the second elements, and h to the last elements?

{
{f[1], g[2], h[3]},
{f[11], g[22], h[33]},
{f[111], g[222], h[333]},
{f[1111], g[2222], h[3333]}
}


(I know a few methods, but I'm looking for more.)

• @J.M. I know, which is why I'm amused that three answers below are using it. – Mr.Wizard Sep 30 '12 at 9:50
• @Mr.Wizard You sure it were you? Have a look here, here, and here,for example :-). – Leonid Shifrin Sep 30 '12 at 13:26
• @Leonid three replies come to mind: (1) You don't think I actually read all that stuff do you? (2) I'm senile and I have no idea why they trust me with the keys. (3) Great minds think alike. -- Take your pick. – Mr.Wizard Sep 30 '12 at 13:42
• @Mr.Wizard I'dpick #3 :-). Besides, neither of us started the trend, it was started by the designer of mma, responsible for Compose (in this case, most likely Stephen Wolfram himself). – Leonid Shifrin Sep 30 '12 at 13:46
• @WReach, if my opinion counts for anything, I was bummed when they "replaced" Compose[] with Composition[]. Oh well... – J. M. is in limbo Sep 30 '12 at 14:06

Inner[#2@#1 &, list, fns, List, 2]


or

Inner[Compose, fns, Transpose@list, List] (* Note, that Compose is obsolete *)


or

MapIndexed[fns[[Last@#2]]@#1 &, list, {2}]


or

ListCorrelate[{fns}, list, {1, -1}, {}, Compose, Sequence]


or

MapThread[Compose, {Array[fns &, Length@list], list}, 2]


or

ReplacePart[list, {i_, j_} :> fns[[j]][list[[i, j]]]]


or

list // Query[All, Thread[Range@Length@fns -> fns]]


or (cheating a little)

list // Query[All, {1 -> f, 2 -> g, 3 -> h}]

• The Inner approach is the one I'm currently using. – Brett Champion Sep 30 '12 at 1:28
• I added another method to make up for it :) – WReach Sep 30 '12 at 1:48
• Like J.M. says Compose has been obsolete since more than 20(!) years. – stevenvh Oct 3 '12 at 17:12
• @steven, that's nothing; Mathematica 8 still has Release[], and that has been deprecated far longer... – J. M. is in limbo Oct 3 '12 at 17:16
• @J.M. "far longer" seems a bit difficult; according to the documentation center both are obsolete since version 2 (1991), and I can't imagine functions being deprecated starting version 1 :-). – stevenvh Oct 3 '12 at 17:19

Map[MapThread[Compose, {fns, #}] &, list]


or

Transpose@MapThread[Map, {fns, Transpose[list]}]

• Like J.M. says Compose has been obsolete since more than 20(!) years. – stevenvh Oct 3 '12 at 17:13
• @stevenvh And so :-) ? – Leonid Shifrin Oct 3 '12 at 17:15
• @steven, it may not exactly be recommended, but it still works. From an old army saw: "if a dumb thing works, then it ain't dumb." – J. M. is in limbo Oct 3 '12 at 17:23
• @Leonid - The documentation center doesn't give any description of it any more, so how can it help OP, when he doesn't know what it does? (You don't explain it either) – stevenvh Oct 4 '12 at 15:53
• @stevenvh Fair enough. I will add the description. But I guess the OP would know what it is, in this particular case, given his affiliation :-) – Leonid Shifrin Oct 4 '12 at 15:58

The OP said: "I know a few methods, but I'm looking for more." so here are my offerings for the sake of interest. The second is intentionally a bit convoluted. The third may actually be of interest as the method could be used for in-place modification.

With[{op = MapIndexed[#[Slot @@ #2] &, fns]}, op & @@@ list]

Fold[RotateLeft@MapAt[#2, #, 1] &, list\[Transpose], Function[x, x /@ # &] /@ fns]\[Transpose]

Module[{x = list\[Transpose]}, Table[x[[i]] = fns[[i]] /@ x[[i]], {i, Length@x}]; x\[Transpose]]


Or for in-place modification:

With[{x = list}, Table[x[[All, i]] = fns[[i]] /@ x[[All, i]], {i, Length@First@x}]; x]


This post is primarily to provide the service of comparative timings. I will be using Mathematica 7.

Timings using an array of 1.5 million Integers and three inert symbolic heads:

fns = {f, g, h};
list = RandomInteger[1*^6, {500000, 3}];
times = timeAvg[#[]] & /@ methods;


Using an array of Reals and three trig functions:

fns = {Sin, Cos, Csc};
list = RandomReal[1*^6, {500000, 3}];
times = timeAvg[#[]] & /@ methods;


To explore performance with different shapes here is as above but with 500 random trig functions:

fns = RandomChoice[{Sin, Cos, Sec, Csc, Tan}, 500];
list = RandomReal[1*^6, {5000, 500}];
times = timeAvg[#[]] & /@ methods;


Functions as I named and used them:

SetAttributes[timeAvg, HoldFirst]
timeAvg[func_] :=
Do[If[# > 0.3, Return[#/5^i]] & @@ Timing@Do[func, {5^i}], {i, 0, 15}]

leonid1[] := Map[MapThread[Compose, {fns, #}] &, list]
rm1[]     := Replace[list, x_List :> MapIndexed[fns[[First@#2]]@#1 &, x], {1}]
rm2[]     := MapIndexed[fns[[First@#2]]@#1 &, #] & /@ list
kguler1[] := Inner[#1@#2 &, fns, #, List] & /@ list
kguler2[] := Inner[Compose, fns, #, List] & /@ list
wreach1[] := Inner[#2@#1 &, list, fns, List, 2]
wreach2[] := MapIndexed[fns[[Last@#2]]@#1 &, list, {2}]
wreach3[] := ListCorrelate[{fns}, list, {1, -1}, {}, Compose, Sequence]
wreach4[] := MapThread[Compose, {Array[fns &, Length@list], list}, 2]
wizard1[] := With[{op = MapIndexed[#[Slot @@ #2] &, fns]}, op & @@@ list]
wizard2[] := Fold[RotateLeft@MapAt[#2, #, 1] &, list\[Transpose], Function[x, x /@ # &] /@ fns]\[Transpose]
wizard3[] := Module[{x = list\[Transpose]}, Table[x[[i]] = fns[[i]] /@ x[[i]], {i, Length@x}]; x\[Transpose]]

methods = {leonid1, leonid2, rm1, rm2, kguler1, kguler2, wreach1,
wreach2, wreach3, wreach4, wizard1, wizard2, wizard3};

Inner[#1@#2 &, fns, #, List] & /@ list
(*or *)
Inner[Compose, fns, #, List] & /@ list
% //TableForm


• Like J.M. says Compose has been obsolete since more than 20(!) years. – stevenvh Oct 3 '12 at 17:14
• @stevenvh And it still works just fine, thank you. :D – Mr.Wizard Jul 15 '14 at 8:42

Another solution using MapIndexed and —

1. Replace:

Replace[list, x : {_, _, _} :> MapIndexed[fns[[First@#2]]@#1 &, x], {1}]

2. Map:

MapIndexed[fns[[First@#2]]@#1 &, #] & /@ list


Here is another option using Compose:

Compose@@@Thread@{fns, #}&/@list


or with Function:

Thread[fns~Function[{f, v}, f@v, Listable]~#] & /@ list


This is not a complete answer, but I am posting it as one so it does not get lost in the comments. Compose has returned in Version 12 as Construct, so all solutions can now be implemented with supported and documented functions.

• Maybe should note that Compose[f, x] is equivalent to Construct[f, x] but Compose[f, g, x] is not equivalent to Construct[f, g, x]. – Michael E2 Jan 8 at 21:00
• @MichaelE2, thank you for noting this. I suspect from watching the design reviews online that there may be a builtin function that will solve this whole problem in 12.1 as it seems to have caught Wolfram's attention. – Daniel W Jan 8 at 21:25