【问题标题】:Clojure Zipper to EDNClojure 拉链到 EDN
【发布时间】:2015-02-20 11:16:27
【问题描述】:

我使用 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 中创建一个可视化,所以我想以 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。

【问题讨论】:

  • ["A" ["B" "C" "D"["E" "F"]]] 不代表你认为的vector-zip的树
  • 您能以适当的方式回复吗? @cgrand see this post
  • vector-zip 无法遍历你想要的树。 ["A" ["B" "C" "D"["E" "F"]]] 代表一棵有两个孩子的树:"A"(一个叶子)和["B" "C" "D"["E" "F"]](一个有 4 个孩子的子树:3 个叶子和一个本身有两个叶子 "E""F" 的子树)。跨度>
  • 其中一个答案是否解决了您的问题?

标签: clojure zipper


【解决方案1】:

你可以稍微改变一下你的树的语法,将一对父子存储在一个向量中,然后滚动你自己的拉链。例如

(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}

【讨论】:

    【解决方案2】:

    我认为@cfrick 的回答是有道理的。在你的树向量中有成对的 [parent [children]] 会更方便。但尽管如此,这里有一个解决方案,您可以保留您的结构并使用vector-zip

    parent-node 获取当前拉链并返回定义结构中的父节点。例如,当拉链在节点 :c 上时,parent-node 返回 :a

    edge-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})
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-05-07
      • 2020-11-05
      • 1970-01-01
      • 2015-04-10
      • 1970-01-01
      • 2013-08-09
      • 2014-06-14
      • 1970-01-01
      相关资源
      最近更新 更多