2

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?

user64494
  • 26,149
  • 4
  • 27
  • 56
Picaud Vincent
  • 2,463
  • 13
  • 20

1 Answers1

3

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|>|>|>|>
Kuba
  • 136,707
  • 13
  • 279
  • 740
  • That's much shorter indeed, thanks – Picaud Vincent Jun 05 '19 at 09:09
  • 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? – Picaud Vincent Jun 05 '19 at 10:19
  • 1
    @PicaudVincent isn't "c" -> 3 gone after the second call? – Kuba Jun 05 '19 at 10:22
  • yep, I have not seen that, thanks for the clarification – Picaud Vincent Jun 05 '19 at 10:29