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 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
add comment

11 Answers

up vote 16 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
add comment

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
    
This one deserves more credit, +1 –  Rojo May 18 '12 at 20:31
    
Thank you @Rojo. –  kguler May 18 '12 at 21:43
add comment
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? –  Rojo 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 –  Rojo 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 –  Rojo May 18 '12 at 20:26
show 1 more comment

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. –  David Carraher 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. –  David Carraher May 19 '12 at 13:43
add comment

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
add comment

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
add comment

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
add comment

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
add comment

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
add comment
A /. a_?(StringMatchQ[#, DigitCharacter ..] &) :> f[a] // Quiet
share|improve this answer
add comment

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

MapAt[f,A,{All,All,1}]
share|improve this answer
3  
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
add 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.