Message Boards Message Boards

GROUPS:

Unfolding a nested association

Posted 1 month ago
212 Views
|
2 Replies
|
3 Total Likes
|

I'm embarrassed by my code because there has to be a better way to do it. Here's a hierarchical list of lab tests Category --> Class --> Test --> Status

<|"Asphaltene" -> <|"Flocculation Point Apparatus" -> <|"FPA" -> 
      "Not started"|>, 
   "Miscellaneous Asphaltenes" -> <|"Asphaltene Content (Heptane \
Insolubles)" -> "Not started"|>|>, 
 "General Characterization" -> <|"Chemical Stability" -> <|"Long Term \
HT Stability" -> "Not started", 
     "Long Term Low Temp Stability" -> "Not started"|>, 
   "Pour Point" -> <|"Pour Point" -> "Not started"|>|>|>

I want to turn it into this:

Asphaltene - Flocculation Point Apparatus - FPA
Asphaltene - Miscellaneous Asphaltenes - Asphaltene Content (Heptane Insolubles)
General Characterization - Chemical Stability - Long Term HT Stability
General Characterization - Chemical Stability - Long Term Low Temp Stability
General Characterization - Pour Point - Pour Point

There has to be a shortcut I'm not thinking of so consider this a fun coding challenge to write the shortest form of the following function:

(*A function to unfold an association*)
unfoldAssociation[association_] := 
     KeyValueMap[With[{key = #1, val = #2},
        If[
         ListQ[val],
         Function[v, <|key -> v|>] /@ val,
         <|key -> val|>]
        ] &, association]
(*Map it at each level*)
unfold3LevelAssociation[association_]:=Block[{temp},
  temp=Map[
    unfoldAssociation,association,
    {2}];
  temp=Flatten/@Map[
    unfoldAssociation,temp,
    {1}];
  temp=FixedPoint[Normal,unfoldAssociation[temp]/.Rule->List//Flatten]/.Rule->List;
  Partition[Flatten[temp],4]
]
(*apply the unfold3layer function and do some formatting - drop the last column*)
unfold3LevelAssociation[lProjectList[[1]]["Test Statuses"]];
StringRiffle[#, " - "] & /@ %[[;; , ;; 3]] // TableForm

It works but it's ugly. What magic function does this in one line?

2 Replies
Posted 1 month ago

Eric,

Take a look at this. A really elegant solution.

associationFlatten[assoc_Association] := 
 Association[Normal[KeyMap[List, assoc]] //. (n_ -> m_Association) :> 
  Normal[KeyMap[Append[n, #] &, m]]]

Use it on your example

assoc = <|"Asphaltene" -> <|
    "Flocculation Point Apparatus" -> <|"FPA" -> "Not started"|>, 
    "Miscellaneous Asphaltenes" -> <|
      "Asphaltene Content (Heptane Insolubles)" -> "Not started"|>|>, 
  "General Characterization" -> <|
    "Chemical Stability" -> <|
      "Long Term HT Stability" -> "Not started", 
      "Long Term Low Temp Stability" -> "Not started"|>, 
    "Pour Point" -> <|"Pour Point" -> "Not started"|>|>|>


associationFlatten[assoc] // Keys // Map[StringRiffle[#, " - "] &] // Column
(*
Asphaltene - Flocculation Point Apparatus - FPA
Asphaltene - Miscellaneous Asphaltenes - Asphaltene Content (Heptane Insolubles)
General Characterization - Chemical Stability - Long Term HT Stability
General Characterization - Chemical Stability - Long Term Low Temp Stability
General Characterization - Pour Point - Pour Point
*)

Or using Alan Calvitti's "magic bullet"

associationFlatten[assoc] // Keys // Map[StringRiffle[\[Bullet], " - "]] // Column

Nice! Thanks for the link and the solution.

I was convinced there was some trick with ListCorrelate or some esoteric function that I didn't know about. I guess the tried and true pattern matching is the answer.

Reply to this discussion
Community posts can be styled and formatted using the Markdown syntax.
Reply Preview
Attachments
Remove
or Discard

Group Abstract Group Abstract