Search code examples
vectorclojurearray-map

How to Add a New Node to Hash-Map Graph in Clojure?


I have the following array-map created in Clojure.

{:node 7, :children [{:node 8, :children []} {:node 6, :children []} {:node 23, :children {}} {:node 43, :children []}]}

How do i go about adding elements into this, running the following code

(def tree (assoc-in tree [:node] 12))

gives me

{:node 12, :children [{:node 8, :children []} {:node 6, :children []} {:node 10, :children {}} {:node 13, :children []} {:node 28, :children []}]}`

and running

(def tree (assoc-in tree [:node :children] 12))

gives me the following error message. how do i add elements into the children sections on the array-map

Exception in thread "main" java.lang.ClassCastException: java.lang.Long cannot be cast to clojure.lang.Associative,

Solution

  • Let's assign our tree to t:

    (def t {:node 7, 
            :children [{:node 8, :children []} 
                       {:node 6, :children []} 
                       {:node 23, :children []} 
                       {:node 43, :children []}]})
    

    To add a new child note:

    (defn add-child [tree node]
      (assoc-in tree 
                [:children] 
                (conj (:children tree) node)))
    
    (add-child t :foo)
    ;; => {:node 7, 
    ;;     :children [{:node 8, :children []} 
    ;;                {:node 6, :children []} 
    ;;                {:node 23, :children []} 
    ;;                {:node 43, :children []} 
    ;;                :foo]}
    

    Of course this is not exactly what we want.

    (defn make-node [value children] 
      (let [c (into [] children)] 
        {:node value 
         :children c}))
    
    (make-node 5 nil)
    ;; => {:node 5, :children []}
    
    (make-node 5 [(make-node 3 nil) (make-node 7 nil)])
    ;; => {:node 5, 
    ;;     :children [{:node 3, :children []} 
    ;;                {:node 7, :children []}]}
    

    Building trees is now a matter of combining make-node & add-child.

    If you want to work on deep hierarchies, I suggest using a zipper.