简体   繁体   中英

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,

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 .

for adding a new node, the basic idea is general. anyway, the prog needs to know where to place the new child. when arriving the parent node of the new child, the prog appends the new child to it. the rest problem is how to traverse a graph in clojure. clojure.walk module is for that purpose.

one implementation of adding a new node to your graph is as follows:

(defn tree-add
  [root parent-key new-node]
  (clojure.walk/postwalk #(if (= parent-key (:node %))
                            (assoc % :children (conj (:children %) new-node))
                            %)
                         root))

testing:

user> a
{:node 7, :children [{:node 8, :children []}]}
user> (tree-add a 7 {:node 99 :children []})
{:node 7, :children [{:node 8, :children []} {:node 99, :children []}]}
user> (tree-add a 8 {:node 199 :children []})
{:node 7, :children [{:node 8, :children [{:node 199, :children []}]}]}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM