7

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

JJM
  • 905
  • 4
  • 10
  • 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. – m_goldberg Feb 07 '16 at 23:02
  • Note that this works: AssociateTo[m2[["M"]], "b" -> 3]; m2. Strongly related discussion can be found here. – Leonid Shifrin Feb 07 '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. – Leonid Shifrin Feb 07 '16 at 23:05
  • Not sure why the downvotes - this looks like a perfectly legitimate question to me. – Leonid Shifrin Feb 07 '16 at 23:07
  • Not sure why the close votes either. Did someone have a bad day today? – Leonid Shifrin Feb 07 '16 at 23:08
  • @LeonidShifrin. AtomQ on a association returns True. – m_goldberg Feb 07 '16 at 23:12
  • @m_goldberg AtomQ on a association returns True - which is rather unfortunate, and this was done mostly to forbid pattern-matching inside associations like other expressions, and also to avoid making Association explicitly HoldAllComplete. But I didn't mean this fact, but the other things you stated about mutability and in-place modifications. Associations are clearly not atomic for part extraction and modifications, despite returning True on AtomQ. – Leonid Shifrin Feb 07 '16 at 23:14
  • @LeonidShifrin. I view associations as being more like complex numbers than like lists in terms of mutability. Perhaps the analogy is ill-conceived, but nothing I've read has so far convinced me to discard it. – m_goldberg Feb 07 '16 at 23:19
  • 1
    @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. – Leonid Shifrin Feb 07 '16 at 23:22
  • @LeonidShifrin Thanks for the reference, very well written. – JJM Feb 07 '16 at 23:23
  • @m_goldberg In fact, there are even much simpler pieces of evidence here, e.g. how Map and similar functions work on assocs. – Leonid Shifrin Feb 07 '16 at 23:23
  • @JJM Glad if that was helpful. – Leonid Shifrin Feb 07 '16 at 23:24

1 Answers1

2

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

Edmund
  • 42,267
  • 3
  • 51
  • 143
  • 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 08 '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. – Edmund Feb 08 '16 at 11:36