9
$\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$
13
$\begingroup$

Not pretty but works:

lst //. x : {__Rule} :> Association[x]
| improve this answer | |
$\endgroup$
  • 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.

| improve this answer | |
$\endgroup$
  • $\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.

| improve this answer | |
$\endgroup$
  • $\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|>|> *)
| improve this answer | |
$\endgroup$
  • 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}]
| improve this answer | |
$\endgroup$
  • $\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.