# Apply multiple functions to parts of a nested list [duplicate]

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?

• Thank you for editing my question, and thank you all for your answers. I think this is a nice problem to demonstrate how powerful functional programming is with Mathematica and how flexible one can be using any of these functions. I have learned a lot from the comparison of all these approaches to the solution of the problem. – Athanassios Jul 13 '16 at 13:16
• I knew it had the be here already: a list of functions onto a list of (lists of) values – Kuba Jul 17 '16 at 7:52

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]

• Just what I was going to post myself… :) – J. M. will be back soon Jul 12 '16 at 22:08
• Great, a very powerful use of the Inner, and yes that generalizes also the problem, thank you MarcoB – Athanassios Jul 12 '16 at 22:11
• @march why not an answer? p.s. worth to mention Compose, (28779) – Kuba Jul 13 '16 at 7:21
• @Kuba. Right you are! I have added it to my post. – march Jul 13 '16 at 16:39

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]


or

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


or

data // Replace[#, {a_, b_, c_, d_} :> {f@a, g@b, h@c, m@d}, 1] &

• Thank you @Sascha, that is nice and clean and definitely shorter than mine ;-) – Athanassios Jul 12 '16 at 22:03
• 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
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

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]]

• (+1) ... or ♯ = (# /@ {##2} & @@@ ({#, ## & @@ #2})) &; ♯[functions, data]` :) – kglr Jul 14 '16 at 1:43