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$

1 Answer 1

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$
4
  • $\begingroup$ That's much shorter indeed, thanks $\endgroup$ Jun 5, 2019 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$ Jun 5, 2019 at 10:19
  • 1
    $\begingroup$ @PicaudVincent isn't "c" -> 3 gone after the second call? $\endgroup$
    – Kuba
    Jun 5, 2019 at 10:22
  • $\begingroup$ yep, I have not seen that, thanks for the clarification $\endgroup$ Jun 5, 2019 at 10:29

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.