1
$\begingroup$

What's the syntax to use individual replacement rules for key-value patterns?

This returns only the first match:

<|"a" -> 1, "b" -> 2|> /. {KeyValuePattern["a" -> x_] :> x + 10, 
  KeyValuePattern["b" -> x_] :> x + 100}

11

And this throws a ReplaceAll error:

<|"a" -> 1, "b" -> 2|> /. 
 KeyValuePattern[{("a" -> x_) :> x + 10, ("b" -> x_) :> x + 100}]

"!({KeyValuePattern[{((\"a\" -> x_)) :> x + 10, ((\"b\" -> x_)) :> x + 100}]}) is neither a list of replacement rules nor a valid dispatch table, and so cannot be used for replacing"

The desired behavior is what you'd expect from List:

{"a" -> 1,"b" -> 2} /. {("a" -> x_) :> x + 10, ("b" -> x_) :> x + 100}

{11,102}

EDIT

Note the List version will match individual key-value pairs, eg:

{"a" -> 1} /. {("a" -> x_) :> x + 10, ("b" -> x_) :> x + 100}

{11}

The solution should match and replace individual key-value pairs in the Association.

(Want to avoid Normal to list as this is a minimal example but in practice the values are nested Associations.)

$\endgroup$
  • $\begingroup$ @kglr, that doesn't work for me in v12 (I copy-pasted your code verbatim), I get the input back in the output unmatched. $\endgroup$ – alancalvitti Jun 7 at 17:23
  • $\begingroup$ @kglr, please see my updated comment - it doesn't work at all. $\endgroup$ – alancalvitti Jun 7 at 17:25
  • $\begingroup$ sorry, miscopied; should be <|"a" -> 1, "b" -> 2|> /. KeyValuePattern[{"a" -> x_, "b" ->y_}]:>{ x+10, y + 100} $\endgroup$ – kglr Jun 7 at 17:25
  • 1
    $\begingroup$ @kglr, no that doesn't work as intended, Since it won't match individual key-values, eg <|"a" -> 1|> /. KeyValuePattern[{"a" -> x_, "b" -> y_}] :> {x + 10, y + 100} - will update my Q to make that explicit. $\endgroup$ – alancalvitti Jun 7 at 17:30
  • $\begingroup$ If your first example had worked, it would have returned the malformed Association[ 11, 102]. If you had just the two replacement rules that you have, what would you want returned from <|"a" ->3, "c" -> 4|> or <|"a"-> <|"b"->2|>, "b" ->7|>? $\endgroup$ – Jason B. Jun 7 at 19:05
2
$\begingroup$

ReplaceList seems to work:

<|"a" -> 1, "b" -> 2|> // 
 ReplaceList[{KeyValuePattern["a" -> x_] :> x + 10, 
   KeyValuePattern["b" -> x_] :> x + 100}]

{11, 102}

<|"a" -> 1|> // 
 ReplaceList[{KeyValuePattern["a" -> x_] :> x + 10, 
   KeyValuePattern["b" -> x_] :> x + 100}]

{11}

And it also seems to almost* handle a workaround to another KeyValuePattern issue - by design it only matches the first key, even though there may be multiple keys that match a given key-pattern:

<|{"a", "x"} -> 1, {"b", "y"} -> 2, {"a", "z"} -> 3|> // 
 ReplaceList[{KeyValuePattern[{"a", k_} -> x_] :> {k, x + 10}, 
   KeyValuePattern[{"b", k_} -> x_] :> {k, x + 100}}]

{{"x", 11}, {"z", 13}, {"y", 102}}

*almost = does not preserve input key order.

I've asked support to add an Option MatchAllKeys` since typically that's more useful that matching only the first one.

$\endgroup$
0
$\begingroup$

Maybe you can use KeyValueMap instead:

KeyValueMap[#1 /. {"a" :> #2 + 10, "b" :> #2 + 100}&] @ <|"a" -> 1, "b" -> 2|>

{11, 102}

or:

KeyValueMap[
    Function[{key, value}, key->value /. {("a"->x_) -> x+10, ("b"->x_) -> x+100}]
] @ <|"a" -> 1, "b" -> 2|>

{11, 102}

Second example:

assoc = <|{"a","x"}->1,{"b","y"}->2,{"a","z"}->3|>;
KeyValueMap[#1 /. {{"a",k_} :> {k,#2+10}, {"b", k_} :> {k,#2+100}}&] @ assoc

{{"x", 11}, {"y", 102}, {"z", 13}}

$\endgroup$
  • $\begingroup$ thanks but in practice as mentioned in the Q, the values are actually associations so want to avoid Slot/Part as vestiges of the 20th century. $\endgroup$ – alancalvitti Jun 8 at 19:21

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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