10
$\begingroup$

Considering we have a list of rules:

In[11]:= lst = {a -> {1 -> {A1, A2, A3, A4}, b -> 2}, c -> {3 -> C3, 4 -> C4}}

Out[11]= {a -> {1 -> {A1, A2, A3, A4}, b -> 2}, c -> {3 -> C3, 4 -> C4}}

Trying to make this an association parses only the beginning and the end of the list of rule:

In[13]:= Association@lst

Out[13]= <|a -> {1 -> {A1, A2, A3, A4}, b -> 2}, c -> {3 -> C3, 4 -> C4}|> 

The output I would like to have is:

<|a -> <|1 -> {A1, A2, A3, A4}, b -> 2|>, c -> <|3 -> C3, 4 -> C4|>|>

How can I parse this?

Thanks!

$\endgroup$
0
13
$\begingroup$

Not pretty but works:

lst //. x : {__Rule} :> Association[x]
$\endgroup$
2
  • 1
    $\begingroup$ Wondering, why do you use {__Rule} and not {_Rule} ? $\endgroup$
    – penguin77
    Apr 9 '15 at 16:45
  • 1
    $\begingroup$ @penguin77 {_Rule} stands for something like {a->2} while we need to match one or more rules: {a->2, b->3...}. $\endgroup$
    – Kuba
    Apr 9 '15 at 16:48
18
$\begingroup$

The undocumented function ToAssociations in the GeneralUtilities package does this

In[3]:= Needs["GeneralUtilities`"]

In[4]:= ToAssociations[lst]

(* Out[4]= <|a -> <|1 -> {A1, A2, A3, A4}, b -> 2|>, 
c -> <|3 -> C3, 4 -> C4|>|> *)

As with any undocumented function, use with caution, as contents tend to shift during flight.

$\endgroup$
1
  • 1
    $\begingroup$ This is now also available as ResourceFunction["ToAssociations"]. $\endgroup$
    – Carl Lange
    Apr 30 '19 at 17:45
4
$\begingroup$

This works too and it's theoretically faster than ReplaceRepeated (//.):

asc = Replace[list, r : {__Rule} :> Association[r], {0, Infinity}]

The key observation is that Replace starts with the innermost levels first and works its way outwards. In contrast, ReplaceAll and ReplaceRepeated start with the outermost levels and work their way inwards.

$\endgroup$
4
  • $\begingroup$ It's interesting to me that the reverse does not work, i.e.: Replace[list, r : <|___Rule|> :> List[r], {0, Infinity}] $\endgroup$
    – geordie
    Nov 26 '18 at 10:41
  • 1
    $\begingroup$ @geordie Association is atomic. Its innards cannot be matched directly. There are tools like KeyValuePattern to extract information during matching. But what you'd do here is something like a_?AssociationQ :> Normal[a]. $\endgroup$
    – Szabolcs
    Nov 26 '18 at 11:11
  • $\begingroup$ Thanks for clarifying. I'm still wrapping my head around Association as a useful construct. Lists of rules seem elegant enough! $\endgroup$
    – geordie
    Nov 26 '18 at 11:19
  • 1
    $\begingroup$ @geordie The main reason is performance. Associations will always be faster, often much faster, then lists of rules. There is also a clear and concise syntax for extracting data, which does not exist for rule lists. $\endgroup$
    – Szabolcs
    Nov 26 '18 at 12:11
0
$\begingroup$

I tried this with a couple of different level specifications in Map, but it seems once the outer List becomes an Association, the other levels of Map are not used. So, instead, we apply it twice:

Map[Association]@Association@lst
(* <|a -> <|1 -> {A1, A2, A3, A4}, b -> 2|>, c -> <|3 -> C3, 4 -> C4|>|> *)
$\endgroup$
6
  • 1
    $\begingroup$ Then you have to apply it so many times as deep target rules are: {a -> {1 -> {A1, A2, A3, A4}, b -> {b1 -> 1, b2 -> 2}}, c -> {3 -> C3, 4 -> C4}} $\endgroup$
    – Kuba
    Apr 9 '15 at 13:18
  • $\begingroup$ @Kuba for the OPs exact input, this works. But, you are correct, it isn't very general. $\endgroup$
    – rcollyer
    Apr 9 '15 at 13:20
  • $\begingroup$ This goes to any level lst //. x : {__Rule} :> Inactive[Association] @@ x // Activate $\endgroup$
    – Daniel W
    Apr 9 '15 at 13:20
  • $\begingroup$ @DanielW that's pretty ugle. I like yours better. $\endgroup$
    – rcollyer
    Apr 9 '15 at 13:21
  • $\begingroup$ Ok, just wanted to say this. $\endgroup$
    – Kuba
    Apr 9 '15 at 13:23
0
$\begingroup$

I played around with the levelspec of Map and apparently this combination works. I have no idea what magic makes this work, though:

Map[Association, lst, {-6, -3}]

Or the following (from @Kuba's simultaneous edit):

Map[Association, lst, {0, -3}]
$\endgroup$
1
  • $\begingroup$ I tried something similar but it won't work if Values are going to be non atomic: {a -> {1 -> {A1, A2, A3, A4}, b -> {b1 -> 1, b2 -> f[s[g[h]]]}}, c -> {3 -> C3, 4 -> C4}}. $\endgroup$
    – Kuba
    Apr 9 '15 at 13:22

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