# 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}} ? – b.gatessucks Apr 7 '12 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 – Eiyrioü von Kauyf Apr 7 '12 at 20:29
Related question: stackoverflow.com/questions/8580113/… – Leonid Shifrin Apr 8 '12 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? – Eiyrioü von Kauyf Apr 7 '12 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 '12 at 21:00
is it possible to do this in a one-liner? – Eiyrioü von Kauyf Apr 7 '12 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[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] – Eiyrioü von Kauyf Apr 8 '12 at 17:16
@EiyrioüvonKauyf MapAt[Log[b, #] &, #, {2, 2}] & /@ data – Vitaliy Kaurov Apr 8 '12 at 18:48

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. – Eiyrioü von Kauyf Apr 7 '12 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. – Artes Apr 7 '12 at 22:11
thanks! I'll try – Eiyrioü von Kauyf Apr 7 '12 at 22:12
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. – Artes Apr 7 '12 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. – Pillsy Apr 9 '12 at 16:02

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


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


These both assume that func is Listable.

-

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

-