2
$\begingroup$

Given a list of keys {"a","b","c"} and a value 3 (associated to the last key) I want to define a function that is equivalent to this manual procedure:

w=<||>;
w["a"]=<||>;
w["a"]["b"]=<||>;
w["a"]["b"]["c"]=3;
w

prints:

<|"a" -> <|"b" -> <|"c" -> 3|>|>|>

From {"a","b","c"}->3, it must create keys/values going deeper in the hierarchy.


The solution I have written so far is:

setKeyValue[assoc_Association,{keys___,keyLast_}->value_]:=
    Block[{tmp,var,keysAsList},
          keysAsList={keys};
          tmp=FoldList[If[KeyExistsQ[#1,#2],#1[#2],<||>]&,assoc,keysAsList];
          tmp=Reverse[Partition[Riffle[Prepend[keysAsList,Null],tmp],2]];
          tmp=Fold[{First[#2],(var=Last[#2];AssociateTo[var,First[#1]->Last[#1]])}&,{keyLast,value},tmp];
          Last[tmp]
    ];

Example with expected behavior:

v=<||>;
v=setKeyValue[v,{"a","b","c"}->3]
v=setKeyValue[v,{"a","b","e","f"}->6]

prints

<|"a" -> <|"b" -> <|"c" -> 3|>|>|>
<|"a" -> <|"b" -> <|"c" -> 3, "e" -> <|"f" -> 6|>|>|>|>

However this function looks so over-complicated that I am sure it exists a more elegant approach.

Any idea?

$\endgroup$
3
$\begingroup$

Using MergeNested from How to organically merge nested associations? we can define AssociateNested:

MergeNested = If[MatchQ[#, {__Association}], Merge[#, #0], Last[#]] &;

AssociateNested[org_Association, path_List, value_] := MergeNested[
  {org, Fold[<|#2 -> #|> &, value, Reverse@path]}
]

Example:

v = <||>;

v = AssociateNested[v, {"a", "b", "c"}, 3]
<|"a" -> <|"b" -> <|"c" -> 3|>|>|>
v = AssociateNested[v, {"a", "b", "e", "f"}, 6]
<|"a" -> <|"b" -> <|"c" -> 3, "e" -> <|"f" -> 6|>|>|>|>
$\endgroup$
  • $\begingroup$ That's much shorter indeed, thanks $\endgroup$ – Picaud Vincent Jun 5 at 9:09
  • $\begingroup$ The solution works, however I do not understand the reason of using the recursive MergeNested. The simpler AssociateNested[org_Association, path_List, value_] := Merge[{org, Fold[<|#2 -> #|> &, value, Reverse@path]},Association] seems to work too. There is certainly something I miss. May you provide some clarification? $\endgroup$ – Picaud Vincent Jun 5 at 10:19
  • 1
    $\begingroup$ @PicaudVincent isn't "c" -> 3 gone after the second call? $\endgroup$ – Kuba Jun 5 at 10:22
  • $\begingroup$ yep, I have not seen that, thanks for the clarification $\endgroup$ – Picaud Vincent Jun 5 at 10:29

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.