Attempting to modify parts of a multi-level association in-place

Generate a simple two-level association

In[1]:= m2 = <|"M" -> <|1 -> {1, 2, 3}, 2 -> {2, 3}|>, "F" -> <|1 -> {}, 2 -> {}|>|>

Out[1]= <|M-><|1->{1,2,3},2->{2,3}|>,F-><|1->{},2->{}|>|>


Show that m2["M"] is an L-value (assignable) of type association

In[2]:= Head[m2["M"]]

Out[2]= Association

In[3]:= m2["M"] = <|1 -> {1}, 2 -> {1, 2}|>; m2

Out[3]= <|M-><|1->{1},2->{1,2}|>,F-><|1->{},2->{}|>|>


AssociateTo is HoldFirst, it should pass m2["M"] unevaluated to be treated as an L-value

In[4]:= Attributes[AssociateTo]

Out[4]= {HoldFirst, Protected}

In[5]:= AssociateTo[m2["M"], "b" -> 3]; m2


During evaluation of In[5]:= AssociateTo::rvalue: m2(M) is not a variable with a value, so its value cannot be changed. >>

Out[5]= <|M-><|1->{1},2->{1,2}|>,F-><|1->{},2->{}|>|>


I don't understand exactly why this fails. I am trying to do an in-place modification of the bottom level of a nested association. I was hoping to use the ideas of Use Scan vs. Map to accomplish this, but it appears that AssociateTo is behaving in an unexpected way. Is there a way to accomplish this, perhaps using "Replacing parts of held expression?".

• Associations are treated as atomic under most operations and, therefore, can not be modified in-place. Your concept of an association as kind of structure as found in procedure languages is, unfortunately for you, wrong. Feb 7 '16 at 23:02
• Note that this works: AssociateTo[m2[["M"]], "b" -> 3]; m2. Strongly related discussion can be found here. Feb 7 '16 at 23:03
• @m_goldberg Your statement is incorrect. Associations are given certain degree of (user-level) mutability, when stored in a symbol, just as lists are. Check out my answer I linked to, in the previous comment, for a longer discussion of this. Feb 7 '16 at 23:05
• Not sure why the downvotes - this looks like a perfectly legitimate question to me. Feb 7 '16 at 23:07
• @m_goldberg " but nothing I've read has so far convinced me to discard it." - well, how about in-place modifications? Like the one with Set on the top of this post, which works perfectly. Or many more examples, both in the docs and in my post I linked above. In my view, they are much closer to lists (arrays), than to complex numbers - they have similar mutability properties, and both are indexed containers of elements. Feb 7 '16 at 23:22

You can create/assign a key/value directly by using the resetting values syntax.

m2 = <|"M" -> <|1 -> {1, 2, 3}, 2 -> {2, 3}|>, "F" -> <|1 -> {}, 2 -> {}|>|>;

m2["M"]["b"] = 3;

m2
(* <|"M" -> <|1 -> {1, 2, 3}, 2 -> {2, 3}, "b" -> 3|>, "F" -> <|1 -> {}, 2 -> {}|>|> *)


This is the last example case in the Basic Examples subsection of the Examples section of the Association documentation.

Hope this helps

• Thanks. I included an example of using Set in this way in my original question. My issue was with simulated pass by reference for expressions like m2["M"][1]. Leonid's linked article cleared up the matter for me.
– JJM
Feb 8 '16 at 11:10
• I see your question above uses 'AssociateTo' to add '"b"'. I am showing how you don't need to call any functions to create '"b"'' in place. Feb 8 '16 at 11:36