Mathematica Stack Exchange is a question and answer site for users of Mathematica. It's 100% free, no registration required.

Sign up
Here's how it works:
  1. Anybody can ask a question
  2. Anybody can answer
  3. The best answers are voted up and rise to the top

I have the following sample list (my actual list is, of course, much longer):

A={{{"15", "CG"}, {"391", "CG"}, {"412", "CC3"}}, {{"3", "CG"}, 
    {"16", "CG"}, {"392", "CG"}}};

I would like to map an arbitrary function f onto the string representation of numbers, like this:

{{{f["15"], "CG"}, {f["391"], "CG"}, {f["412"], "CC3"}}, {{f["3"], "CG"}, 
  {f["16"], "CG"}, {f["392"], "CG"}}}

Is there a straightforward, succinct way of doing this using Map, MapAt, or something else? Unlike Map, it seems that MapAt does not have an option with levelspec.

share|improve this question

11 Answers 11

up vote 18 down vote accepted

A combination of Map and MapAt perhaps?

Map[MapAt[f, #, 1] &, A, {2}]

(* ===>  {{{f["15"], "CG"}, {f["391"], "CG"}, {f["412"], "CC3"}}, 
         {{f["3"], "CG"}, {f["16"], "CG"}, {f["392"], "CG"}}} 
*)
share|improve this answer

To map f to number strings appearing at any position or depth:

Map[If[StringMatchQ[#, NumberString], f[#], #] &, A, {-1}]
(* => {{{f["15"], "CG"}, {f["391"], "CG"}, {f["412"], "CC3"}}, {{f["3"], "CG"}, {f["16"], "CG"}, {f["392"], "CG"}}} *)

another example:

b = {{{"15", "CG"}, {{"391", "CG"}, "230"}, {"412", "CC3"}}, {{"3", 
 "CG"}, {"392", {"CG", {"CG", "345"}}}}};
Map[If[StringMatchQ[#, NumberString], f[#], #] &, b, {-1}]
(* => {{{f["15"], "CG"}, {{f["391"], "CG"}, f["230"]}, {f["412"], "CC3"}}, {{f["3"], "CG"}, {f["392"], {"CG", {"CG", f["345"]}}}}} *)
share|improve this answer
1  
This one deserves more credit, +1 – Rojolalalalalalalalalalalalala May 18 '12 at 20:31
    
Thank you @Rojo. – kglr May 18 '12 at 21:43

More options:

Apply[{f[#1], ##2} &, A, {2}]

{f[#1], ##2} & @@@ # & /@ A

ReplacePart[A, {i_, j_, 1} :> f @ A[[i, j, 1]] ]

ReplacePart[A, p:{_, _, 1} :> f @ Extract[A, p] ]
share|improve this answer
    
+1 For the graffiti. – DavidC May 19 '12 at 13:15
    
@David I'm not sure how to read that; is the code hard to read? (I think ReplacePart is quite readable myself.) – Mr.Wizard May 19 '12 at 13:21
    
The second example would be difficult to read for the newly initiated in mma. My +1 more accurately reflects my amazement at your skill in crafting so many different solutions. – DavidC May 19 '12 at 13:43
A[[All, All, 1]] = Map[f, A[[All, All, 1]], {2}]

I think the neatest given the question is probably a mix between David Carraher and kguler's

A /. x_String /; StringMatchQ[x, NumberString] :> f[x]

or a little bit more efficiently, searching only the lowest levels

Replace[A, x_String /; StringMatchQ[x, NumberString] :> f[x], {-1}]
share|improve this answer
    
This solution intrigues me, but I don't think it all got posted – Jagra May 18 '12 at 20:16
    
It makes the changes in place. Why does it intrigue you @Jagra? – Rojolalalalalalalalalalalalala May 18 '12 at 20:19
    
A construct (A[[All,All,1]] =), that I just never thought of using before. Except I can't get it work properly ;-( – Jagra May 18 '12 at 20:23
1  
@Jagra, since the changes are made in place, you can use it only once. If you run it twice, you get f[f["23"]], etc – Rojolalalalalalalalalalalalala May 18 '12 at 20:25
1  
Also, don't look at the output of that line. Look at the value of A after running the line – Rojolalalalalalalalalalalalala May 18 '12 at 20:26

I like to use @@ (or @@@ on lists) since #1 is easier to read than #[[1]] in the middle (muddle) of more brackets:

Map[{f[#1], #2} & @@ # &, A, {2}]

{{{f["15"], "CG"}, {f["391"], "CG"}, {f["412"], "CC3"}}, {{f["3"], 
   "CG"}, {f["16"], "CG"}, {f["392"], "CG"}}}
share|improve this answer

Try a very simple idea:

A = {{{"15", "CG"}, {"391", "CG"}, {"412", "CC3"}}, {{"3", 
     "CG"}, {"16", "CG"}, {"392", "CG"}}};

g[{x_, y_}] := {f[x], y};

Map[g, A, {2}]
{{{f["15"], "CG"}, {f["391"], "CG"}, {f["412"], "CC3"}}, {{f["3"], 
   "CG"}, {f["16"], "CG"}, {f["392"], "CG"}}}
share|improve this answer

Perhaps

 g = # /. {a_String, b_String} :>  {f[a], b} &;
 g@A

yielding

{{{f["15"], "CG"}, {f["391"], "CG"}, {f["412"], "CC3"}}, {{f["3"], 
"CG"}, {f["16"], "CG"}, {f["392"], "CG"}}}
share|improve this answer

Another possibility, which I don't think has been given (but is similar to other answers):

Map[{f@First@#, Last@#} &, A, {2}]
share|improve this answer

As @Kuba shows here, now in version 9 you can do:

MapAt[f,A,{All,All,1}]
share|improve this answer
4  
It might be nice to mention that Kuba brought this to your attention. – Mr.Wizard Aug 27 '13 at 4:25
    
I agree. Done :) – Murta Aug 27 '13 at 11:24
    
even MapAt[f,A,{;;,;;,1}] – garej Jan 29 at 9:22

Map on map does the job nicely:

{f[#[[1]]], #[[2]]} & /@ # & /@ A

{{{f[15],CG},{f[391],CG},{f[412],CC3}},{{f[3],CG},{f[16],CG},{f[392],CG}}}
share|improve this answer
A /. a_?(StringMatchQ[#, DigitCharacter ..] &) :> f[a] // Quiet
share|improve this answer

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.