Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Appending into nested associative structures

Tags:

clojure

I have a structure that I created at the REPL,

{1 {10 {:id 101, :name "Paul"}, 
    20 {}}, 
2 {30 {}, 40 {}}, 
3 {50 {}, 60 {}}}

and I want to add a new k v to the key 1, such that the resulting structure looks like this,

{1 {10 {:id 101, :name "1x2"}, 20 {}, 11 {:id 102, :name "Ringo"}},
 2 {30 {}, 40 {}}, 3 {50 {}, 60 {}}}.

I just discovered get-in update-in and assoc-in for working with nested structures like these, but cannot figure out how to add new elements within elements. In my app this is all wrapped in a ref and updated with dosync/alter, but for now, I just want to be able to do this at the REPL.

Maybe I've just been looking at this too long, but any attempt to use assoc or assoc-in just changes what is already there, and does not append new elements.

like image 808
JPT Avatar asked Feb 24 '23 18:02

JPT


1 Answers

Given your input

(def input
  {1 {10 {:id 101 :name "Paul"}
      20 {}}
   2 {30 {} 40 {}}
   3 {50 {} 60 {}}})

You can use assoc-in to add an element to the nested map with key 1 like this:

(assoc-in input [1 11] {:id 102 :name "Ringo"})

which yields

{1 {10 {:id 101 :name "Paul"}
    11 {:id 102 :name "Ringo"}
    20 {}}
 2 {30 {} 40 {}}
 3 {50 {} 60 {}}}

Assoc-in doesn't need to point all the way to the deepest level of a structure.

If you use two calls to assoc-in you can use the second one to change the name "Paul" to "1x2" as per your example:

(assoc-in
  (assoc-in input [1 11] {:id 102 :name "Ringo"})
  [1 10 :name] "1x2"))

Which returns

{1 {10 {:id 101 :name "1x2"}
    11 {:id 102 :name "Ringo"}
    20 {}}
 2 {30 {} 40 {}}
 3 {50 {} 60 {}}}
like image 87
Gert Avatar answered Mar 03 '23 10:03

Gert