14

Suppose that I have a this list of associations

   data = {<|"axis" -> x, "model" -> a, "p1" -> 1, "p2" -> 2|>,
           <|"axis" -> x, "model" -> b, "p1" -> 3, "p2" -> 4|>,
           <|"axis" -> y, "model" -> a, "p1" -> 5, "p2" -> 6|>,
           <|"axis" -> y, "model" -> b, "p1" -> 7, "p2" -> 8|>}

and I group the data into a nested association form:

grouped = GroupBy[data, 
                  {Key["axis"] -> KeyDrop["axis"],
                   Key["model"] -> KeyDrop["model"]},
                  First]

<|x -> <|a -> <|"p1" -> 1, "p2" -> 2|>,
         b -> <|"p1" -> 3, "p2" -> 4|> |>, 
  y -> <|a -> <|"p1" -> 5, "p2" -> 6|>,
         b -> <|"p1" -> 7, "p2" -> 8|> |> |>

How could you reverse this operation?

I have found a way to reverse it but it is very convoluted:

grouped // 
   AssociationMap[
    Function[{rule1}, 
     Keys[rule1] -> (AssociationMap[
        Function[{rule2}, 
         Keys[rule2] -> 
          Prepend[Values@rule2, {"axis" -> Keys[rule1], 
            "model" -> Keys[rule2]}]], Values[rule1]])]] //
  Query[Values, Values] //
 Flatten

I am looking for a more readable way to do this. Ideally one would use something like MatAt but as far as I know one cannot access values from higher levels on nested associations like this.

Gustavo Delfino
  • 8,348
  • 1
  • 28
  • 58

1 Answers1

17

This looks a little simpler:

Catenate @ MapIndexed[
  Append[#,Thread[{"axis", "model"} -> Replace[#2, Key[x_] :> x, {1}] ]] &, 
  grouped, 
  {2}
]

(* 
   {
     <|"p1" -> 1, "p2" -> 2, "axis" -> x, "model" -> a|>, 
     <|"p1" -> 3, "p2" -> 4, "axis" -> x, "model" -> b|>, 
     <|"p1" -> 5, "p2" -> 6, "axis" -> y, "model" -> a|>, 
     <|"p1" -> 7, "p2" -> 8, "axis" -> y, "model" -> b|>
   }
*)

I didn't care about the order of keys, but if it matters, it can be easily fixed too.

EDIT

Generalization by WReach:

ungroup[keys_][assocs_] := 
  With[{l = {Length@keys}}, 
    Level[
      MapIndexed[<|Thread[keys -> #2[[All, 1]]], #|> &, assocs, l], 
      l
    ]
  ]

This can be used as:

ungroup[{"axis", "model"}][grouped]

And in this particular case, yields the same result, but can be used also for more (or less) deep nesting.

END EDIT

Leonid Shifrin
  • 114,335
  • 15
  • 329
  • 420