我使用Clojure Zipper创建了以下图表
A
/ | \
B C D
/ \
E F
使用以下代码:
(require '[clojure.zip :as z])
(def g (z/vector-zip ["A" ["B" "C" "D"["E" "F"]]]))
现在我想在d3中创建一个Visualization,这样我想用EDN格式表示图形,
[{:from "A" :to "B"}
{:from "A" :to "C"}
{:from "A" :to "D"}
{:from "D" :to "E"}
{:from "D" :to "F"}]
我试过这个
(loop [t g]
(if-not (z/end? t)
(do
(if-not (z/branch? t)
(println {:from (-> t (get 1) :ppath :l) :to (z/node t)})
)
(recur (z/next t))
)
)
)
唯一的问题是儿童E& F,我无法跟踪其父节点D.
答案 0 :(得分:1)
您可以稍微更改树的语法,以便在向量中存储一对父级和子级,然后滚动自己的拉链。 E.g。
(def v [\a [\b [\c [\z]] [\d [\e \f]]]])
(def g
(z/zipper
vector? ; a vector/pair is a branch
#(concat (second %)) ; might be a smarter way to get the childs
nil ; don't support edit
v))
(loop [t (z/next g)] ; skip first
(if-not (z/end? t)
(do
(println {
:from (-> t z/up z/node first) ; parents are always vectors
:to (if (z/branch? t) (-> t z/node first) (z/node t))}) ; if vector, then first
(recur (z/next t)))))
;;=> {:from a, :to b}
;;=> {:from a, :to c}
;;=> {:from c, :to z}
;;=> {:from a, :to d}
;;=> {:from d, :to e}
;;=> {:from d, :to f}
答案 1 :(得分:0)
我认为@cfrick的回答是有道理的。在树矢量中使用[parent [children]]对更方便。但是,这是一个解决方案,您可以保留您的结构并使用vector-zip
。
parent-node
获取当前拉链并返回define结构中的父节点。例如,当拉链在节点:c
上时,parent-node
返回:a
。
edge-seq
构建图边缘的lazy-seq。过滤特定边缘可能很有用。
(defn edges [vtree]
(letfn [(parent-node [vz]
(if-not (-> vz z/node vector?)
(-> vz
z/up
z/left
(#(when % (z/node %))))))
(edge-seq [vz]
(if-not (z/end? vz)
(if-let [p (parent-node vz)]
(cons {:from p :to (z/node vz)}
(lazy-seq (edge-seq (-> vz z/next))))
(edge-seq (-> vz z/next)))))]
(let [vz (z/vector-zip vtree)]
(edge-seq vz))))
使用以下向量/树:
user> (def v [:a [:b :c :d [:e [:h] :f] :g]])
#'user/v
user> (pprint (edges v))
({:from :a, :to :b}
{:from :a, :to :c}
{:from :a, :to :d}
{:from :d, :to :e}
{:from :e, :to :h}
{:from :d, :to :f}
{:from :a, :to :g})
仅保留:d
user> (pprint (filter #(= :d (:from %)) (edges v)))
({:from :d, :to :e} {:from :d, :to :f})