14
data = {{1, a, x, "one"}, {2, b, y, "two"}, {3, c, z, "three"}}

I want to apply a list of four functions

{f, g, h, m}

one for each element of these nested lists respectively. One solution I have come up with is the following:

MapAt[m,
 MapAt[h,
  MapAt[g,
   MapAt[f, data, {All, 1}], {All, 2}], {All, 3}], {All, 4}]
{{f[1], g[a], h[x], m["one"]},
 {f[2], g[b], h[y], m["two"]},
 {f[3], g[c], h[z], m["three"]}}

But I do not consider this an elegant solution because I cannot find a way to escape from the MapAt nested repetition. Could you possibly show me the way to generalize the problem and/or suggest a different answer?

Karsten7
  • 27,448
  • 5
  • 73
  • 134
Athanassios
  • 1,291
  • 10
  • 22

5 Answers5

15
data = {{1, a, x, "one"}, {2, b, y, "two"}, {3, c, z, "three"}};
functions = {f, g, h, m};

Inner[#2[#1] &, data, functions, List]

(* Out: 
  {{f[1], g[a], h[x], m["one"]}, 
   {f[2], g[b], h[y], m["two"]}, 
   {f[3], g[c], h[z], m["three"]}}
*)

With reversing the order of functions and data, to fully harness the functional style without using slots:

 Inner[Compose, functions, Transpose@data, List]
István Zachar
  • 47,032
  • 20
  • 143
  • 291
MarcoB
  • 67,153
  • 18
  • 91
  • 189
5
data // Replace[#, {a_, b_, c_, d_} :> {f@a, g@b, h@c, m@d}, 1] &
Athanassios
  • 1,291
  • 10
  • 22
Sascha
  • 8,459
  • 2
  • 32
  • 66
  • Thank you @Sascha, that is nice and clean and definitely shorter than mine ;-) – Athanassios Jul 12 '16 at 22:03
  • 3
    If the list is four elements long, there will be a problem. Instead, use Replace with a level-spec: Replace[{{1, a, x, "one"}, {2, b, y, "two"}, {3, c, z, "three"}}, {a_, b_, c_, d_} :> {f@a, g@b, h@c, m@d}, 2] – march Jul 12 '16 at 22:13
5

Not quite as nice and concise as the Inner solution, but still worth writing down I think:

MapThread[#1@#2 &, {Table[functions, {Length@data}], data}, 2]
MapThread[Compose, {Table[functions, {Length@data}], data}, 2]

or

MapThread[#1@#2 &, {functions, #}] & /@ data
MapThread[Compose, {functions, #}] & /@ data

or

march
  • 23,399
  • 2
  • 44
  • 100
4
Needs["GeneralUtilities`"]

MultiMapAt[Transpose[{ConstantArray[All, #], Range@#}]&[Length@functions], functions][data]
{{f[1], g[a], h[x], m["one"]}, {f[2], g[b], h[y], m["two"]}, 
 {f[3], g[c], h[z], m["three"]}}

Which does the same as

(Composition @@ MapThread[MapAt, {functions, {{All, 1}, {All, 2}, {All, 3}, {All, 4}}}])@data
Karsten7
  • 27,448
  • 5
  • 73
  • 134
4
data = {{1, a, x, "one"}, {2, b, y, "two"}, {3, c, z, "three"}};
functions = {f, g, h, m};

Late for the party:

Transpose[# /@ {##2} & @@@ Transpose @ Prepend[data, functions]]
Kuba
  • 136,707
  • 13
  • 279
  • 740
  • 1
    (+1) ... or ♯ = (# /@ {##2} & @@@ ({#, ## & @@ #2})) &; ♯[functions, data] :) – kglr Jul 14 '16 at 01:43