9
$\begingroup$

This question already has an answer here:

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$

marked as duplicate by Mr.Wizard Jul 4 '15 at 0:29

This question has been asked before and already has an answer. If those answers do not fully address your question, please ask a new question.

12
$\begingroup$

Not pretty but works:

lst //. x : {__Rule} :> Association[x]
$\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
17
$\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$
  • $\begingroup$ This is now also available as ResourceFunction["ToAssociations"]. $\endgroup$ – Carl Lange Apr 30 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$
  • $\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$
  • 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$
  • $\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.