Take the 2-minute tour ×
Mathematica Stack Exchange is a question and answer site for users of Mathematica. It's 100% free, no registration required.

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.

share|improve this question
    
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
2  
Related question: stackoverflow.com/questions/8580113/… –  Leonid Shifrin Apr 8 '12 at 11:34
add comment

8 Answers

up vote 5 down vote accepted

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]}} *)
share|improve this answer
    
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
1  
@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
add comment

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]}}
share|improve this answer
add comment

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.

share|improve this answer
add comment

when f is listable, use Set and Part:

a = {{1, 2}, {4, 2}, {6, 4}};
a[[All, 2]] = Log@a[[All, 2]];
a
share|improve this answer
add comment

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

share|improve this answer
    
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
add comment

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]
share|improve this answer
add comment

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

share|improve this answer
add comment

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.

share|improve this answer
    
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
1  
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
show 1 more comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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