Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/clojure/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Graph 从Clojure中表示为向量的树中获取边_Graph_Clojure_Tree_Edges - Fatal编程技术网

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