Does anyone know a way to use patterns in Query?
There is no built-in facility to do this kind of transformation, but we can define our own query operator like so:
patterned[template:PatternSequence[_Rule...]][data_Association] :=
Module[{x}
, data //
Query[Replace[Keys[data], Append[x:# :> x -> #2 & @@@ {template}, _ -> Nothing], {1}]]
]
So then:
assoc // Query[patterned["a"|"d" -> f]]
(* <| "a" -> f[{1,3,2,9,4}], "b" -> {6,1,8},
"c" -> {3,2,8,9,8}, "d" -> f[{5}], "e" -> {5,3} |> *)
assoc // Query[patterned["a"|"c" -> f, Except["b"] -> h, _ -> g]]
(* <| "a" -> f[{1, 3, 2, 9, 4}], "b" -> g[{6, 1, 8}],
"c" -> f[{3, 2, 8, 9, 8}], "d" -> h[{5}], "e" -> h[{5, 3}]|> *)
Since I am not aware of any built-ins, here is another custom solution:
MapAtPattern[p_ -> f_, expr_] := MapIndexed[
If[MatchQ[#2[[1]], Key@p],
f@#,
#
] &,
expr
]
MapAtPattern[spec_][expr_] := MapAtPattern[spec, expr]
MapAtPattern[rules_List,
expr_] := (RightComposition @@ MapAtPattern /@ rules)@expr
It supports essentially the syntax from your question:
assoc = <|1 -> {1, 3, 2, 9, 4}, "b" -> {6, 1, 8},
2.1 -> {3, 2, 8, 9, 8}, 2 -> {5}, "e" -> {5, 3}|>;
MapAtPattern[{"a" | "b" | "c" -> f, _ -> g, Except["b"] -> h}]@assoc
(* <|
1 -> h[g[{1, 3, 2, 9, 4}]],
"b" -> g[f[{6, 1, 8}]],
2.1 -> h[g[{3, 2, 8, 9, 8}]],
2 -> h[g[{5}]],
"e" -> h[g[{5, 3}]]
|> *)
It can also be used as part of a more complex Query
:
Query[MapAtPattern@{"a" | "b" | "c" -> f, _ -> g, Except["b"] -> h}]@assoc
(* same output *)
As you can see, every matching rule is applied, not only the first (in contrast to the answer from @WReach)