# 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. Sep 30, 2012 at 9:50
• @Mr.Wizard You sure it were you? Have a look here, here, and here,for example :-). Sep 30, 2012 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. Sep 30, 2012 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). Sep 30, 2012 at 13:46
• @WReach, if my opinion counts for anything, I was bummed when they "replaced" Compose[] with Composition[]. Oh well... Sep 30, 2012 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. Sep 30, 2012 at 1:28
• I added another method to make up for it :) Sep 30, 2012 at 1:48
• Like J.M. says Compose has been obsolete since more than 20(!) years. Oct 3, 2012 at 17:12
• @steven, that's nothing; Mathematica 8 still has Release[], and that has been deprecated far longer... Oct 3, 2012 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 :-). Oct 3, 2012 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. Oct 3, 2012 at 17:13
• @stevenvh And so :-) ? Oct 3, 2012 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." Oct 3, 2012 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) Oct 4, 2012 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 :-) Oct 4, 2012 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. Oct 3, 2012 at 17:14
• @stevenvh And it still works just fine, thank you. :D Jul 15, 2014 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]. Jan 8, 2020 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. Jan 8, 2020 at 21:25

Sorry for bothering an old question. It's not that fast but here is one way with the newer Threaded:

Function[, #1@#2, {Listable}][Threaded@fns, list]

• (+1) I like updates like this one!!!
– bmf
Jan 11, 2023 at 12:00
• @bmf Thanks! Though not the fastest, the performance of Threaded is not bad. I guess people on this site haven't got into habit of using it (yet). Jan 11, 2023 at 12:13

Yet another solution:

Transpose[Activate[Thread[Inactive[Map][fns, Transpose[list]]]]]


Just another way:

Transpose@Diagonal[(Thread /@ Through[fns[#]]) & /@ (Transpose@list)]

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


Or using Outer:

Transpose@Diagonal[Transpose@*Thread@*Through /@ Outer[fns @@ #1 &@*List,Transpose@list]]

• Nicely done mate - comment/reminder to upvote - I used max votes today
– bmf
Jan 11, 2023 at 15:59
• Hi, mate! We are starting the year with a lot of energy :-) Jan 11, 2023 at 16:10