5
$\begingroup$

I want to extract only the deepest level of association in a nested associations.

An example of input data is

<|a -> 1, b -> <|x -> p, y -> <|z -> 3, w -> "a"|>|>|>

and I need to get

<|a -> 1, x -> p, z -> 3, w -> "a"|>

I have seen several questions similar to this but I have not been able to solve the problem.

What is the best way to do this?

Thanks!

$\endgroup$

5 Answers 5

5
$\begingroup$
test1 = <|a -> 1, b -> <|x -> p, y -> <|z -> 3, w -> "a"|>|>|>
Association[Level[test1 /. Association -> List, {-2}]]
(* <|a -> 1, x -> p, z -> 3, w -> "a"|> *)

Update

To address the comment about needing to handle the cases where the values of the lowest level associations might be lists...

test2 = <|a -> 1, b -> <|c -> 1, d -> {2, 3}|>|>
Association[Normal[test1] //. (_ -> val_Association) :> Splice[Normal[val]]]
(* <|a -> 1, x -> p, z -> 3, w -> "a"|> *)

Association[Normal[test2] //. (_ -> val_Association) :> Splice[Normal[val]]]
(* <|a -> 1, c -> 1, d -> {2, 3}|> *)

Probably want to bundle into a function:

AssociationLeaves[a_Association] := 
  Association[Normal[a] //. (_ -> val_Association) :> Splice[Normal[val]]]
$\endgroup$
1
  • $\begingroup$ Concise solution, thanks! $\endgroup$
    – user14061
    Commented Oct 27, 2023 at 4:36
3
$\begingroup$
asc = <|a -> 1, b -> <|x -> p, y -> <|z -> 3, w -> "a"|>|>|>

asc /. Association -> List // Level[#, {-2}] & // Association

<|a -> 1, x -> p, z -> 3, w -> "a"|>


Or

Normal@asc //. {HoldPattern[a_ -> b_ /; ! AssociationQ[b]] :> a -> b, 
    HoldPattern[a_ -> b_ /; AssociationQ[b]] :> Normal@b} // 
  Flatten // Association

Result:

<|a -> 1, x -> p, z -> 3, w -> "a"|>

$\endgroup$
2
  • $\begingroup$ Thanks! The latter example was a little difficult for me, but I think I understand it somehow. $\endgroup$
    – user14061
    Commented Oct 27, 2023 at 4:38
  • $\begingroup$ The latter seems necessary when the association contains lists as data. (ex) asc = <|a -> 1, b -> <|c -> 1, d -> {2, 3}|>|>; $\endgroup$
    – user14061
    Commented Oct 27, 2023 at 4:51
3
$\begingroup$
flattenA // ClearAll
flattenA[a_Association]     := Association @ Flatten @ KeyValueMap[flattenA] @ a
flattenA[k_, v_Association] := KeyValueMap[flattenA] @ v;
flattenA[k_, v_]            := k -> v

flattenA@<|a -> 1, b -> <|x -> p, y -> <|z -> 3, w -> "a"|>|>|>

<|a -> 1, x -> p, z -> 3, w -> "a"|>

$\endgroup$
2
  • $\begingroup$ This gives Association[ Flatten[KeyValueMap[flattenA][<|a -> 1, b -> <|x -> p, y -> <|z -> 3, w -> "a"|>|>|>]]]. $\endgroup$
    – Syed
    Commented Oct 27, 2023 at 6:59
  • 1
    $\begingroup$ @Syed sorry, made a typo, corrected. $\endgroup$
    – Kuba
    Commented Oct 27, 2023 at 7:25
2
$\begingroup$
asc = <|a -> 1, b -> <|x -> p, y -> <|z -> 3, w -> "a"|>|>|>;

NestWhile[
 Association@
   KeyValueMap[
    If[AssociationQ@#2, #2, # -> #2] &, #] &, asc, UnsameQ, 2]

(* Output *)
<|a -> 1, x -> p, z -> 3, w -> "a"|>
$\endgroup$
2
  • 1
    $\begingroup$ also FixedPoint[Association@*KeyValueMap[If[AssociationQ@#2, #2, # -> #2] &], asc] (+1) $\endgroup$
    – kglr
    Commented Oct 28, 2023 at 17:51
  • $\begingroup$ @kglr Nice one, thanks! $\endgroup$
    – vindobona
    Commented Oct 28, 2023 at 22:58
1
$\begingroup$
asc = <|a -> 1, b -> <|x -> p, y -> <|z -> 3, w -> "a"|>|>|>;

Using Fold and MapAt

Association @ Flatten @ Fold[
   MapAt[Last, ##] &,
   asc /. Association :> List,
   {2, {2, 2}}]

<|a -> 1, x -> p, z -> 3, w -> "a"|>

$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.