3
$\begingroup$

Let's consider I have a list of rules:

{Aa -> 1/2, Av -> 2/5, Bx -> 3/7, Ce -> 4/9, ...}

I want to find all keys that contain the letter "A" and change their values to expressions. This means to have as a result:

***Some code here...***
{Aa -> ToExpression[1/2], Av -> ToExpression[2/5], Bx->3/7, Ce->4/9, ...}
$\endgroup$
2
  • 1
    $\begingroup$ if you are afraid of evaluation of Aa.., related: 75294 $\endgroup$
    – Kuba
    Commented Mar 26, 2015 at 13:52
  • 3
    $\begingroup$ Your question implies that some or all the keys and values in your list are strings, but in your post they all look like symbols or rational numbers. Please reformat your example to make the strings explicit. $\endgroup$
    – m_goldberg
    Commented Mar 26, 2015 at 14:42

5 Answers 5

7
$\begingroup$

I would use something like this:

Clear[f];
f[key_ -> val_] := key -> If[
   StringMatchQ[ToString@key, ___ ~~ "A" | "a" ~~ ___], q@val, val]

then

f /@ {Aa->1/2, Av->2/5, Bx->3/7, Ce->4/9}
(* {Aa -> q[1/2], Av -> q[2/5], Bx -> 3/7, Ce -> 4/9} *)

If you have v10, and your data is in an Association, you use AssociationMap, instead:

AssociationMap[f, <|Aa->1/2, Av->2/5, Bx->3/7, Ce->4/9|>
(* <|Aa -> q[1/2], Av -> q[2/5], Bx -> 3/7, Ce -> 4/9|> *)

An alternative to StringMatchQ, which I usually forget about, is StringFreeQ which simplifies the implementation:

Clear[g];
g[key_ -> val_] := key -> If[StringFreeQ[ToString@key, "A" | "a"], val, q@val]
$\endgroup$
2
  • 2
    $\begingroup$ There is StringFreeQ. $\endgroup$
    – Kuba
    Commented Mar 26, 2015 at 14:44
  • $\begingroup$ @Kuba yep. That's one I usually forget exists. $\endgroup$
    – rcollyer
    Commented Mar 26, 2015 at 15:39
5
$\begingroup$

A variation on the theme:

test = {Aa -> "1/2", Av -> "2/5", Bx -> "3/7", Ce -> "4/9"};

test /. (key_ /; 
     StringMatchQ[ToString[key], ___ ~~ "a" | "A" ~~ ___] -> 
    val_) :> (key -> ToExpression[val])

(*{Aa -> 1/2, Av -> 2/5, Bx -> "3/7", Ce -> "4/9"}*)
$\endgroup$
2
$\begingroup$

Try also this:

    as = <|"Aa" -> "1/2", "Av" -> "2/5", "Ca" -> "3/4", "Bx" -> "3/7", 
   "Ce" -> "4/9"|>;
ks = KeySelect[as, 
   Characters[#][[1]] == "A" || Characters[#][[2]] == "a" &];
op = Map[ToExpression, ks, 2];

Merge[{Association[Complement[Normal[as], Normal[ks]]], op}, Total]

yielding

    (*  <|"Bx" -> "3/7", "Ce" -> "4/9", "Aa" -> 1/2, "Av" -> 2/5, "Ca" -> 3/4|
 >   *)
$\endgroup$
1
$\begingroup$
list = {Aa -> "1/2", Av -> "2/5", Bx -> "3/7", Ce -> "4/9"};

Using KeyValueMap (new in 10.1)

KeyValueMap[#1 -> If[StringMatchQ[ToString@#1, "A*"], ToExpression[#2], #2] &] @ 
 Association[list]

{Aa -> 1/2, Av -> 2/5, Bx -> "3/7", Ce -> "4/9"}

$\endgroup$
1
$\begingroup$

Using Fold to build ApplyFunctionIfKeyContains:

ApplyFunctionIfKeyContains[expr_List | expr_Association, fun_, keyPattern_] := Module[
    {isAssociation, normalExpr, result},
    isAssociation = AssociationQ[expr];
    normalExpr = If[isAssociation, Normal @ expr, expr];
    result = Fold[
            Function[
                If[StringContainsQ[ToString[Part[#2, 1]], keyPattern],
                    Append[#, Part[#2, 1] -> fun[Part[#2, 2]]],
                    Append[#, #2]
                ]
            ],
            If[isAssociation, <||>, {}],
            normalExpr
        ];
    If[isAssociation, Association @ result, result]
   ];

Testing ApplyFunctionIfKeyContains:

ApplyFunctionIfKeyContains[{Aa -> 1/2, Av -> 2/5, Bx -> 3/7, Ce -> 4/9}, q, "A" | "a"]

{Aa -> q[1/2], Av -> q[2/5], Bx -> 3/7, Ce -> 4/9}

ApplyFunctionIfKeyContains[<|Aa -> 1/2, Av -> 2/5, Bx -> 3/7, Ce -> 4/9|>, q, "B"]

<|Aa -> 1/2, Av -> 2/5, Bx -> q[3/7], Ce -> 4/9|>

$\endgroup$

Your Answer

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

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