11

I have an association that maps {x, y} pairs to values, for example:

 <|{0, 0} -> "a", {-1, -4} -> "b", {-1, 1} -> "c", {-1, 0} -> "d", {1, 0} -> "e"|>

I want to convert this to a nested association with the outer association keyed by x and the inner by y:

<|0 -> <|0 -> "a"|>, -1 -> <|-4 -> "b", 0 -> "d", 1 -> "c"|>, 1 -> <|0 -> "e"|>|>

My current code is (assuming a is the association):

Apply[Association]@*Map[Last@# -> a[#] &] /@ GroupBy[Keys@a, First, Sort]

but I'm wondering if there's a more elegant way to do this (sorting not necessary).

2012rcampion
  • 7,851
  • 25
  • 44
  • You could also use Association /@ rather than Apply[Association]@* in your code with same results. – MarcoB Jul 30 '17 at 22:54

3 Answers3

8

The following will do the same thing and avoid the sorting, but I am not sure whether it counts as "more elegant" in your book:

assoc = <|{0, 0} -> "a", {-1, -4} -> "b", {-1, 1} -> "c", {-1, 0} -> "d", {1, 0} -> "e"|>;

Association /@
 GroupBy[#[[1, 1]]& -> (#[[1, 2]] -> #[[2]] &)]@
  Normal@assoc

(*Out:  <|0 -> <|0 -> "a"|>, -1 -> <|-4 -> "b", 1 -> "c", 0 -> "d"|>, 1 -> <|0 -> "e"|>|> *)
MarcoB
  • 67,153
  • 18
  • 91
  • 189
7
Merge[
    KeyValueMap[ #[[1]] -> <|#[[2]] -> #2|> &, asso]
  , Association
]
<|0 -> <|0 -> "a"|>, -1 -> <|-4 -> "b", 1 -> "c", 0 -> "d"|>,  1 -> <|0 -> "e"|>|>

For deeper examples {1,2,3,4,1}->"a" etc, you may need MergeNested

Kuba
  • 136,707
  • 13
  • 279
  • 740
  • Kuba, is NestedMerge a new function? It's not documented, or do you mean Nest[Merge,f,n] – alancalvitti Aug 03 '17 at 21:26
  • @alancalvitti I linked it, click it :) – Kuba Aug 03 '17 at 21:38
  • my fault, I thought false highlighting. What are the advantages of NestedMerge viz Nest[Merge,...]? – alancalvitti Aug 03 '17 at 21:49
  • Btw, can you email me re WTC this year if you're going - re planned get together in C-U or Chi? Your contact info lists gluonvision but only Rolf's email shows up there. – alancalvitti Aug 03 '17 at 21:54
  • 1
    @alancalvitti due to personal matters I can't go this year. Would love to meet fellow MMA users again but maybe next year. – Kuba Aug 03 '17 at 22:05
1
keyTrie=Query[keyGroupBy[First]]/*Query[All,KeyMap[Rest]]/*Query[All,If[Keys[#1]=={{}},First[Values[#1]],keyTrie[#1]]&]

This is a recursive query that uses keyGroupBy utility:

keyGroupBy[f_][expr_]:=Association/@GroupBy[Normal[expr],Keys/*f]

To your data:

<|{0, 0} -> "a", {-1, -4} -> "b", {-1, 1} -> "c", {-1, 0} -> 
   "d", {1, 0} -> "e"|> // keyTrie

<|0 -> <|0 -> "a"|>, -1 -> <|-4 -> "b", 1 -> "c", 0 -> "d"|>, 1 -> <|0 -> "e"|>|>

alancalvitti
  • 15,143
  • 3
  • 27
  • 92