Graph 从Clojure中表示为向量的树中获取边
我有一棵这样的树:Graph 从Clojure中表示为向量的树中获取边,graph,clojure,tree,edges,Graph,Clojure,Tree,Edges,我有一棵这样的树: [:root [:a [:b [:c [:g]]]] [:d [:e [:f [:g]]]]] 如何获得边缘,即: [[:root :a] [:root :d] [:a :b] [:b :c] [:c :g] [:d :e] [:e :f] [:f :g]] 没有简单的内置方法可以做到这一点。最简单的方法是滚动自己的递归 这是一个具有唯一hiccup标记(无重复)的解决方案: 单元测试显示输入数据和结果 (dotest (let [tree [:root
[:root
[:a [:b [:c [:g]]]]
[:d [:e [:f [:g]]]]]
如何获得边缘,即:
[[:root :a] [:root :d] [:a :b] [:b :c] [:c :g] [:d :e] [:e :f] [:f :g]]
没有简单的内置方法可以做到这一点。最简单的方法是滚动自己的递归 这是一个具有唯一hiccup标记(无重复)的解决方案: 单元测试显示输入数据和结果
(dotest
(let [tree [:root
[:a
[:b
[:c
[:z]]]]
[:d
[:e
[:f
[:g]]]]]]
(reset! result [])
(walk-with-path! print-edge tree)
(is= @result
[[:root :a] [:a :b] [:b :c] [:c :z]
[:root :d] [:d :e] [:e :f] [:f :g]])))
为了方便起见,如
xfirst
,append
,等等我非常喜欢你发帖的方式斯科特·克拉伦巴赫,它是一种合成的方式
我在原始clojure中提出了一个解决方案。棘手的部分是递归调用的位置以及如何处理这些递归调用的结果
(def数据
[:根
[:a[:b[:c[:g]]]
[:d[:e[:f[:g]]]
(定义获取边[集合]
(let[root(第一个集合)
分支机构(其余集合)]
(如果(空?分支)
[]
(让[边缘]
(mapv(fn[分支][根(第一分支)]分支)
子边
(->)分支
(mapcat(fn[分支](获取边分支)))
(vec)]
(如果(空?子边)
边缘
(vec(混凝土边子边(()())())))
(获取边数据)
;; => [:根:a][:根:d][:a:b][:b:c][:c:g][:d:e][:e:f][:f:g]]
这是我在检查你的答案之前想到的。除非我遗漏了什么,否则看起来有点地道
(defn vec->edges [v-tree]
(->> v-tree
(tree-seq vector? next)
(mapcat (fn [[a & children]]
(map (fn [[b]] [a b]) children)))))
此方法使用基本循环(不需要额外的库或递归): 在示例数据上测试它:
(get-edges [:root
[:a [:b [:c [:g]]]]
[:d [:e [:f [:g]]]]])
;; => [[:root :a] [:root :d] [:d :e] [:e :f] [:f :g] [:a :b] [:b :c] [:c :g]]
以下是另一种基于惰性序列的方法:
(defn get-edges2 [tree]
(->> [tree]
(iterate #(into (rest %) (rest (first %))))
(take-while seq)
(mapcat (fn [subtrees]
(let [[[root & sub] & _] subtrees]
(map #(-> [root (first %)]) sub))))))
这段代码很棒,但它可以简化很多,而不需要真正更改基本算法,特别是删除所有
if
s。我把它简化为:(defn get edges[collection](let[[root&branchs]collection](into(mapv(fn[branch][root(first branch)])branchs)(mapcat get edges)branchs))
。你知道,我从来没有使用过树序列。我甚至忘了它的存在!
(get-edges [:root
[:a [:b [:c [:g]]]]
[:d [:e [:f [:g]]]]])
;; => [[:root :a] [:root :d] [:d :e] [:e :f] [:f :g] [:a :b] [:b :c] [:c :g]]
(defn get-edges2 [tree]
(->> [tree]
(iterate #(into (rest %) (rest (first %))))
(take-while seq)
(mapcat (fn [subtrees]
(let [[[root & sub] & _] subtrees]
(map #(-> [root (first %)]) sub))))))