# How to "flatten" a nested Association?

For example, I have a nested association like this

<|"fff" -> <|"2001" -> <|5040. -> {"S20010037", "S20010038",
"S20010039", "S20010040", "S20010041", "S20010042"}|>,
"2005" -> <|4350. -> {"S20050448", "S20050449"},
3450. -> {"S20050998", "S20050999"}|>|>|>

I want to "Flatten" it like this

<|{fff, 2001, 5040.} -> {"S20010037", "S20010038", "S20010039",
"S20010040", "S20010041", "S20010042"}, {fff, 2005,
4350.} -> {"S20050448", "S20050449"}, {fff, 2005,
3450.} -> {"S20050998", "S20050999"}|>

I can't figure out a good way. How to do it elegantly?

• Sep 30, 2016 at 10:00
• See also associationFlatten function described here: community.wolfram.com/groups/-/m/t/837061?p_p_auth=QuUJXH8q Sep 30, 2016 at 12:21
• @Mr.Wizard Sorry for late comment, these are so useful! Thank you so much! Oct 8, 2016 at 0:12
• @matheorem No problem! I am glad you found them relevant. Oct 8, 2016 at 0:13

Another idea:

FixedPoint[Association[Normal[#] /. Rule[n_, m_Association] :>
KeyMap[Append[n, #] &, m]] &, KeyMap[{#} &, asso]]
<|{"fff", "2001", 5040.} -> {"S20010037", "S20010038", "S20010039",
"S20010040", "S20010041", "S20010042"}, {"fff", "2005",
4350.} -> {"S20050448", "S20050449"}, {"fff", "2005",
3450.} -> {"S20050998", "S20050999"}|>

Which is the same as:

Association[Normal[KeyMap[List, asso]] //.
(n_ -> m_Association) :> Normal[KeyMap[Append[n, #] &, m]]]
• Nice use of FixedPoint. (+1) Sep 30, 2016 at 10:16
• Clever!! +1 : ) Oct 8, 2016 at 0:32

I think this works:

fn[a_ -> _[b__Rule]]  := Flatten[{a, #}] -> #2 & @@@ {b}
fn[x : (_ -> _fn) ..] := Flatten[fn /@ {x}]
fn[a_Association]     := <|a /. Association -> fn|>

Test:

fn[input]   (* input being your input expression *)
<|{"fff", "2001", 5040.} -> {"S20010037", "S20010038", "S20010039", "S20010040",
"S20010041", "S20010042"},
{"fff", "2005", 4350.} -> {"S20050448", "S20050449"},
{"fff", "2005", 3450.} -> {"S20050998", "S20050999"}|>

Perhaps cleaner:

ClearAll[fn]

a_ -> fn[b__] ^:= Flatten[{a, #}] -> #2 & @@@ Flatten[{b}]
fn[a_Association] := a /. Association -> fn
fn[x_List] := <|x|>

I feel as though there should be a simpler form than this but it eludes me at the moment.

asso = <|"fff" -> <|
"2001" -> <|
5040. -> {"S20010037", "S20010038", "S20010039", "S20010040",
"S20010041", "S20010042"}|>,
"2005" -> <|4350. -> {"S20050448", "S20050449"},
3450. -> {"S20050998", "S20050999"}|>|>|>

Ugly but working:

flatten = Association @* Flatten @* KeyValueMap[
If[ MatchQ[#2, _Association],
flatten @ KeyMap[
Function[key, If[MatchQ[#, {_, __}], Append[#, key], {#, key}]],
#2
],
# -> #2
] &
]

f @ asso
<|
{"fff", "2001", 5040.} -> {"S20010037", "S20010038", "S20010039",    "S20010040", "S20010041", "S20010042"},
{"fff", "2005", 4350.} -> {"S20050448", "S20050449"},
{"fff", "2005",3450.} -> {"S20050998", "S20050999"}
|>
• Sorry for late comment. It is Working! Thank you! But for me, Coolwater's answer is easier to understand ; ) Oct 8, 2016 at 0:40