# 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[2]}, {4,Log[2]}, {6,Log[4]} ...}


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 {#[[1]], Log[#[[2]]]} & /@ { {1,2}, {4,2}, {6,4}} ? Commented 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 Commented Apr 7, 2012 at 20:29
• Related question: stackoverflow.com/questions/8580113/… Commented Apr 8, 2012 at 11:34

You can define a function as :

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

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

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


Or you can generalize to :

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

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

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

• 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? Commented 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
Commented Apr 7, 2012 at 21:00
• is it possible to do this in a one-liner? Commented Apr 7, 2012 at 21:01

MapAt and deeply nested lists generalization

Another way to do this:

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


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

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[2]}}}}, {3,{3,{{Log[3]}}}}, {4,{4,{{Log[4]}}}}, {5,{5,{{Log[5]}}}}}

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

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]


when f is listable, use Set and Part:

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


You can use ReplaceAll i.e.

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

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


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. Commented 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. Commented 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. Commented 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. Commented 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. Commented Apr 9, 2012 at 16:39

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[2]}, {4, Log[2]}, {6, Log[4]}}  *)


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[2]}, {4, Log[2]}, {6, Log[4]}}


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) Commented Nov 2, 2020 at 2:59

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[1], f2[2]}, {f1[4], f2[2]}, {f1[6], f2[4]}}


For OP's particular example:

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


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

list = {{1, 2}, {4, 2}, {6, 4}};


Using ReplaceAt (new in 13.1)

ReplaceAt[a_ :> Log[a], {All, 2}] @ list


Using Query

Query[All, {1 -> Identity, 2 -> Log}] @ list


Both return

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

Using SubsetMap:

list = {{1, 2}, {4, 2}, {6, 4}};
SubsetMap[Log, list, {All, 2}]


Result:

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

A minimalistic version of one of @eldo's solutions

m={{1, 2}, {4, 2}, {6, 4}}

Query[All, {2 -> Log}]@m

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

Query[All, {2 -> Log}] // Normal

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


MapAt[Log, {All, 2}]@m

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

• Nice modification / explanation
– eldo
Commented Apr 22 at 22:33