# 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.)

-
Suddenly everybody is using Compose; I think I started a trend. –  Mr.Wizard Sep 30 '12 at 6:48
–  Guess who it is. Sep 30 '12 at 9:46
@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
@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
@WReach, if my opinion counts for anything, I was bummed when they "replaced" Compose[] with Composition[]. Oh well... –  Guess who it is. Sep 30 '12 at 14:06

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


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]

-
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... –  Guess who it is. 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

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

-

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." –  Guess who it is. 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