Association of Associations : how to permute level 1 and level 2 keys?

Mathematica 10.1 almost supports this operation directly:

assoc // Query[Transpose]

(*
<| "a" -> <|"1" -> "x", "2" -> Missing["KeyAbsent", "a"]|>,
   "b" -> <|"1" -> "y", "2" -> "z"|>,
   "c" -> <|"1" -> Missing["KeyAbsent", "c"], "2" -> "k"|>
|>
*)

All that remains is to delete the unwanted Missing elements:

assoc // Query[Transpose] // DeleteMissing[#, 2]&

(*
<| "a" -> <|"1" -> "x"|>,
   "b" -> <|"1" -> "y", "2" -> "z"|>, 
   "c" -> <|"2" -> "k"|>
|>
*)

We can see that Query uses the undocumented function GeneralUtilities`AssociationTranspose to do the heavy-lifting:

Query[Transpose] // Normal

(* GeneralUtilities`AssociationTranspose *)

assoc // GeneralUtilities`AssociationTranspose

(*
<| "a" -> <|"1" -> "x", "2" -> Missing["KeyAbsent", "a"]|>,
   "b" -> <|"1" -> "y", "2" -> "z"|>,
   "c" -> <|"1" -> Missing["KeyAbsent", "c"], "2" -> "k"|>
|>
*)

An Imperative Solution

The words "elegant" and "imperative" rarely appear together these days, but an imperative solution can express the transposition directly:

Module[{r = <| |>}
, Do[r = Merge[{r, <| j -> <| i -> assoc[[i, j]] |> |>}, Association]
  , {i, Keys[assoc]}
  , {j, Keys[assoc[[i]]]}
  ]
; r
]

(*
<| "a" -> <|"1" -> "x"|>,
   "b" -> <|"1" -> "y", "2" -> "z"|>, 
   "c" -> <|"2" -> "k"|>
|>
*)

A ScanIndexed operator would come in handy here (the undocumented one in GeneralUtilities` is not, well, general enough).


Not as nice as what WReach posted but this is what I came up with:

GroupBy[
  Join @@ Thread /@ Normal //@ assoc,
  {First@*Last, First}
][[All, All, 1, 2, 2]]
<|"a" -> <|"1" -> "x"|>, "b" -> <|"1" -> "y", "2" -> "z"|>, "c" -> <|"2" -> "k"|>|>

Here is another version, using KeyValueMap (needs 10.1):

regroup = 
  Composition[
    Map[Association],
    GroupBy[First -> Last],
    Flatten,
    Normal,
    KeyValueMap[Function[{k, v}, Map[k -> # &, v]]]
  ];

So that

regroup @ assoc

(* <|"a" -> <|"1" -> "x"|>, "b" -> <|"1" -> "y", "2" -> "z"|>, "c" -> <|"2" -> "k"|>|> *)

Tags:

Associations