16
$\begingroup$

Is there a nice (built-in) way to apply Replace-style rules to key-value pairs in an association? Something like

SomeFunction[<| "id" -> 3, "freq" -> 4 |>, "freq" -> #freq+1 &] (* should produce <| "id" -> 3, "freq" -> 5 |> *) 

This could also be used to add computed keys, like

SomeFunction[..., "density" -> #mass / #volume &] 

This would be really useful when combining with Query and Dataset.

$\endgroup$

3 Answers 3

20
$\begingroup$

Adding the same key to an Association will replace the previous value, which leads to this solution:

assoc = <| "id" -> 3, "freq" -> 4 |>; <|#, "freq" -> #freq + 1|> &@assoc (* <| "id" -> 3, "freq" -> 5 |> *) 

The following alternatives also work:

assoc["freq"] = 5 assoc["freq"] = assoc["freq"] + 1 assoc["freq"] += 1 
$\endgroup$
3
  • $\begingroup$ Neat. The really interesting part of this isn't that adding a key replaces an existing one, but that you can merge by putting the whole association inside another like <|#, ...|>. $\endgroup$ Commented Jul 14, 2014 at 3:44
  • $\begingroup$ Actually...is that even documented? $\endgroup$ Commented Jul 14, 2014 at 4:06
  • 1
    $\begingroup$ It's as if Association had a Flat attribute. $\endgroup$ Commented Jan 11, 2015 at 21:18
7
$\begingroup$

You can also use KeySelect to operate on keys that meet certain criteria.

assoc = <|"id" -> 3, "freq" -> 4, "fred" -> 2, "geeze" -> 1|>; endsInD = KeySelect[assoc, StringMatchQ[#, __ ~~ "d"] &] 

<|"id" -> 3, "fred" -> 2|>

Merge[ {assoc, #^2 &@endsInD}, Last] 

<|"id" -> 9, "freq" -> 4, "fred" -> 4, "geeze" -> 1|>

$\endgroup$
1
  • $\begingroup$ It's cool that functions like ^ work on the association's values. $\endgroup$ Commented Jul 14, 2014 at 3:45
7
$\begingroup$

You can use AssociateTo to change an existing Association which is already bound to a variable. The definition of your SomeFunction would then look like the following

SetAttributes[SomeFunction, {HoldFirst}]; SomeFunction[a_, func_] := AssociateTo[a, func[a]] 

and you examples work like this

assoc=<|"id"->3,"freq"->4,"mass"->2,"volume"->5|>; SomeFunction[assoc,"freq"->#freq+1&] SomeFunction[assoc,"density"->#mass/#volume&] (* <|id->3,freq->5,mass->2,volume->5|> *) (* <|id->3,freq->5,mass->2,volume->5,density->2/5|> *) 
$\endgroup$

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.