7
$\begingroup$

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?".

$\endgroup$
  • $\begingroup$ 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. $\endgroup$ – m_goldberg Feb 7 '16 at 23:02
  • $\begingroup$ Note that this works: AssociateTo[m2[["M"]], "b" -> 3]; m2. Strongly related discussion can be found here. $\endgroup$ – Leonid Shifrin Feb 7 '16 at 23:03
  • $\begingroup$ @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. $\endgroup$ – Leonid Shifrin Feb 7 '16 at 23:05
  • $\begingroup$ Not sure why the downvotes - this looks like a perfectly legitimate question to me. $\endgroup$ – Leonid Shifrin Feb 7 '16 at 23:07
  • 1
    $\begingroup$ @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. $\endgroup$ – Leonid Shifrin Feb 7 '16 at 23:22
2
$\begingroup$

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

$\endgroup$
  • $\begingroup$ 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. $\endgroup$ – JJM Feb 8 '16 at 11:10
  • $\begingroup$ 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. $\endgroup$ – Edmund Feb 8 '16 at 11:36

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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