Take the 2-minute tour ×
Mathematica Stack Exchange is a question and answer site for users of Mathematica. It's 100% free, no registration required.

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

share|improve this question
    
Suddenly everybody is using Compose; I think I started a trend. –  Mr.Wizard Sep 30 '12 at 6:48
    
1  
@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
1  
@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
1  
@WReach, if my opinion counts for anything, I was bummed when they "replaced" Compose[] with Composition[]. Oh well... –  J. M. Sep 30 '12 at 14:06
show 7 more comments

5 Answers

up vote 17 down vote accepted

How about:

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]
share|improve this answer
    
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. 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
show 1 more comment

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;
BarChart[MapThread[Labeled, {times, methods}]]

Mathematica graphics

Using an array of Reals and three trig functions:

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

Mathematica graphics

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;
BarChart[MapThread[Labeled, {times, methods}]]

Mathematica graphics


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]
leonid2[] := Transpose@MapThread[Map, {fns, Transpose[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};
share|improve this answer
add comment
Inner[#1@#2 &, fns, #, List] & /@ list
(*or *)
Inner[Compose, fns, #, List] & /@ list
% //TableForm

enter image description here

share|improve this answer
    
Like J.M. says Compose has been obsolete since more than 20(!) years. –  stevenvh Oct 3 '12 at 17:14
add comment

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
    
share|improve this answer
add comment

What about

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

or

Transpose@MapThread[Map, {fns, Transpose[list]}]
share|improve this answer
    
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
1  
@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. 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
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.