27
$\begingroup$

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.

$\endgroup$

11 Answers 11

22
$\begingroup$

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"}}} 
*)
$\endgroup$
19
$\begingroup$

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"]}}}}} *)
$\endgroup$
1
  • 1
    $\begingroup$ This one deserves more credit, +1 $\endgroup$
    – Rojo
    May 18, 2012 at 20:31
15
$\begingroup$

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] ]
$\endgroup$
2
  • $\begingroup$ @David I'm not sure how to read that; is the code hard to read? (I think ReplacePart is quite readable myself.) $\endgroup$
    – Mr.Wizard
    May 19, 2012 at 13:21
  • $\begingroup$ 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. $\endgroup$
    – DavidC
    May 19, 2012 at 13:43
14
$\begingroup$
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}]
$\endgroup$
6
  • $\begingroup$ This solution intrigues me, but I don't think it all got posted $\endgroup$
    – Jagra
    May 18, 2012 at 20:16
  • $\begingroup$ It makes the changes in place. Why does it intrigue you @Jagra? $\endgroup$
    – Rojo
    May 18, 2012 at 20:19
  • $\begingroup$ A construct (A[[All,All,1]] =), that I just never thought of using before. Except I can't get it work properly ;-( $\endgroup$
    – Jagra
    May 18, 2012 at 20:23
  • 1
    $\begingroup$ @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 $\endgroup$
    – Rojo
    May 18, 2012 at 20:25
  • 1
    $\begingroup$ Also, don't look at the output of that line. Look at the value of A after running the line $\endgroup$
    – Rojo
    May 18, 2012 at 20:26
12
$\begingroup$

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"}}}
$\endgroup$
11
$\begingroup$

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"}}}
$\endgroup$
10
$\begingroup$

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

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

Map[{f@First@#, Last@#} &, A, {2}]
$\endgroup$
9
$\begingroup$

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

MapAt[f,A,{All,All,1}]
$\endgroup$
3
  • 4
    $\begingroup$ It might be nice to mention that Kuba brought this to your attention. $\endgroup$
    – Mr.Wizard
    Aug 27, 2013 at 4:25
  • $\begingroup$ I agree. Done :) $\endgroup$
    – Murta
    Aug 27, 2013 at 11:24
  • $\begingroup$ even MapAt[f,A,{;;,;;,1}] $\endgroup$
    – garej
    Jan 29, 2016 at 9:22
8
$\begingroup$

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}}}
$\endgroup$
7
$\begingroup$
A /. a_?(StringMatchQ[#, DigitCharacter ..] &) :> f[a] // Quiet
$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

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