# Map and Apply a function on a nested list

I have a list like this:

{{1,2}, {4,2}, {6,4} ... }


I want to replace every second number with a function of that number. For e.g.

{{1, Log}, {4,Log}, {6,Log} ...}


It is ok if the actual number is evaluated e.g. {1, .301} for the first one. I am trying to do this with a combination of Apply, Map and ReplacePart but am having no luck.

I do not understand how to do @@ in cases where the nested list is supplied as an argument to the function.

• Why not {#[], Log[#[]]} & /@ { {1,2}, {4,2}, {6,4}} ? Apr 7, 2012 at 20:25
• what do you mean...? and how do you use #, & and the /@ operator? I assume the last one is the Map operator, but I admit to not knowing how it works except that it will do f[element] for every element in a list where f is a function Apr 7, 2012 at 20:29
• Related question: stackoverflow.com/questions/8580113/… Apr 8, 2012 at 11:34

You can define a function as :

myF[alist_, f_] := Map[{#[], f[#[]]} &, alist]

myF[{{1, 2}, {4, 2}, {6, 4}}, Log]

(* {{1, Log}, {4, Log}, {6, Log}} *)


Or you can generalize to :

myF2[alist_, f_] := Map[{f[][#[]], f[][#[]]} &, alist]

myF2[alist, {# &, Log}]
myF2[alist, {Sin, Log}]

(* {{1, Log}, {4, Log}, {6, Log}} *)
(* {{Sin, Log}, {Sin, Log}, {Sin, Log}} *)

• thanks, this is really comprehensive.. the only problem is, can you explain how "f_", "#", "&" are to be used, and I assume *( and *) represent the output? Apr 7, 2012 at 20:57
• @user997301 I would suggest toe read the very nice tutorial from leonid! Evrything is explained there very well. mathprogramming-intro.org
– Lou
Apr 7, 2012 at 21:00
• is it possible to do this in a one-liner? Apr 7, 2012 at 21:01

Since you seem to be relatively new to Mathematica, and unfamiliar with all its special syntax (/@, @@@ etc), I would normally recommend Artes' second answer:

{#1, Log[#2]} & @@@ {{1, 2}, {4, 2}, {6, 4}}


Which can also be written

Apply[{#1, Log[#2]} &, testdata, {1}]


where testdata = {{1, 2}, {4, 2}, {6, 4}}

Some alternative ways of getting the same answer include:

MapThread[{#1, Log[#2]} &, Transpose@testdata]


and (I think this one is quite cool)

Inner[#1[#2] &, {# &, Log[#] &}, Transpose@testdata, List]


MapAt and deeply nested lists generalization

Another way to do this:

MapAt[Log, #, 2] & /@ {{1,2}, {4,2}, {6,4}}


{{1, Log}, {4, Log}, {6, Log}}

Which is useful if we target a specific element inside every element of a deeply nested list:

data = Table[{k, {k, {{k}}}}, {k, 2, 5}]


{{2, {2, {{2}}}}, {3, {3, {{3}}}}, {4, {4, {{4}}}}, {5, {5, {{5}}}}}

MapAt[Log, #, {2, 2}] & /@ data


{{2,{2,{{Log}}}}, {3,{3,{{Log}}}}, {4,{4,{{Log}}}}, {5,{5,{{Log}}}}}

• how do you do log arguments though, ex. Log[1,2] Apr 8, 2012 at 17:16
• @EiyrioüvonKauyf MapAt[Log[b, #] &, #, {2, 2}] & /@ data Apr 8, 2012 at 18:48

You can use ReplaceAll i.e.

{{1, 2}, {4, 2}, {6, 4}} /. {a_, b_} -> {a, Log[b]}

{{1, Log}, {4, Log}, {6, Log}}


or

{#1, Log[#2]} & @@@ {{1, 2}, {4, 2}, {6, 4}}


i.e. Apply the function {#1, Log[#2]} & on the first level of the expression.

• I believe your second answer works, but not the first one. Apr 7, 2012 at 21:09
• @EiyrioüvonKauyf The first method works too, but if applied to singular cases it may yield unexpected results. In this case a is replaced by {1,c} and b by {2,d}. In general you have to be careful using pattern matching and if you cannot exclude cases when it fails or not sure how to use it better work with Apply. Apr 7, 2012 at 22:11
• My first comment concerned : {{1, c}, {2, d}} /. {a_, b_} -> {a, Log[b]} as an example when it fails to get what you'd like. Apr 7, 2012 at 22:28
• @Artes That problem can be solved using Replace with a level specification of {1}. I remember being mildly surprised when I figured out that Replace was good for something. Apr 9, 2012 at 16:02
• @Pillsy Thanks for a good hint. I see other ways of dealing with patterns here but I find discussing them is out of the scope of this question since there have been given many nice solutions so far. Apr 9, 2012 at 16:39

when f is listable, use Set and Part:

a = {{1, 2}, {4, 2}, {6, 4}};
a[[All, 2]] = Log@a[[All, 2]];
a


partReplace[dat_, func_, spec__] :=
Module[{a = dat},
a[[spec]] = func @ a[[spec]];
a
]

partReplace[{{1, 2}, {4, 2}, {6, 4}}, Log, All, 2]

{{1, Log}, {4, Log}, {6, Log}}


partReplace2[dat_, func_, spec__] := ReplacePart[data, {spec} -> func @ data[[spec]] ]


These both assume that func is Listable.

• ReplacePart didn't work on the recent version (12.0) Nov 2, 2020 at 2:59

MapAt was updated some versions ago (V10? but not documented until V11.1) to handle this use-case. An example similar to this may be found in the documentation:

MapAt[Log, {{1, 2}, {4, 2}, {6, 4}}, {All, 2}]
(*  {{1, Log}, {4, Log}, {6, Log}}  *)


Be careful, some method is really slow. :) The fastest one is always the "vectorization one". • Adding the code used to generate the table would greatly improve this answer. Nov 2, 2020 at 12:41

My explanation of # &, #2 &, ## &, ##2 & can be found in my Mathematica tips and tricks pages as part of the section discussing Function.

Here's a variation of b.gatessucks's generalization:

Map[Composition[Through, {Composition[f1, First], Composition[f2, Last]}],
{{1, 2}, {4, 2}, {6, 4}}]
{{f1, f2}, {f1, f2}, {f1, f2}}


For OP's particular example:

Map[Composition[Through, {Composition[Identity, First], Composition[Log, Last]}],
{{1, 2}, {4, 2}, {6, 4}}]
{{1, Log}, {4, Log}, {6, Log}}