21
$\begingroup$

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.

$\endgroup$
  • $\begingroup$ Why not {#[[1]], Log[#[[2]]]} & /@ { {1,2}, {4,2}, {6,4}} ? $\endgroup$ – b.gates.you.know.what Apr 7 '12 at 20:25
  • $\begingroup$ 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 $\endgroup$ – Eiyrioü von Kauyf Apr 7 '12 at 20:29
  • 2
    $\begingroup$ Related question: stackoverflow.com/questions/8580113/… $\endgroup$ – Leonid Shifrin Apr 8 '12 at 11:34
7
$\begingroup$

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]}} *)
$\endgroup$
  • $\begingroup$ 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? $\endgroup$ – Eiyrioü von Kauyf Apr 7 '12 at 20:57
  • 1
    $\begingroup$ @user997301 I would suggest toe read the very nice tutorial from leonid! Evrything is explained there very well. mathprogramming-intro.org $\endgroup$ – Lou Apr 7 '12 at 21:00
  • $\begingroup$ is it possible to do this in a one-liner? $\endgroup$ – Eiyrioü von Kauyf Apr 7 '12 at 21:01
14
$\begingroup$

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]
$\endgroup$
12
$\begingroup$

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

$\endgroup$
  • $\begingroup$ how do you do log arguments though, ex. Log[1,2] $\endgroup$ – Eiyrioü von Kauyf Apr 8 '12 at 17:16
  • $\begingroup$ @EiyrioüvonKauyf MapAt[Log[b, #] &, #, {2, 2}] & /@ data $\endgroup$ – Vitaliy Kaurov Apr 8 '12 at 18:48
9
$\begingroup$

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.

$\endgroup$
  • $\begingroup$ I believe your second answer works, but not the first one. $\endgroup$ – Eiyrioü von Kauyf Apr 7 '12 at 21:09
  • $\begingroup$ @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. $\endgroup$ – Artes Apr 7 '12 at 22:11
  • 2
    $\begingroup$ 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. $\endgroup$ – Artes Apr 7 '12 at 22:28
  • $\begingroup$ @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. $\endgroup$ – Pillsy Apr 9 '12 at 16:02
  • $\begingroup$ @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. $\endgroup$ – Artes Apr 9 '12 at 16:39
9
$\begingroup$

when f is listable, use Set and Part:

a = {{1, 2}, {4, 2}, {6, 4}};
a[[All, 2]] = Log@a[[All, 2]];
a
$\endgroup$
4
$\begingroup$

From my answer in the thread that Leonid linked:

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

Though this fails on version 7, ruebenko's answer is IMHO the most elegant for recent versions:

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

These both assume that func is Listable.

$\endgroup$
3
$\begingroup$

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]}}  *)
$\endgroup$
1
$\begingroup$

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]}}
$\endgroup$
0
$\begingroup$

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

$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.