Clojure中的树遍历

Clojure中的树遍历,clojure,tree,clojurescript,Clojure,Tree,Clojurescript,考虑一棵树,它由以下递归定义定义: 树应该是两个元素的向量:第一个是数字,第二个是树列表或零 以下clojure数据结构就是一个示例: (def tree '[9 ([4 nil] [6 nil] [2 ([55 nil] [22 nil] [3 ([5 nil])])] [67 ([44 nil])])]) 该结构应转换为所有可

考虑一棵树,它由以下递归定义定义:

树应该是两个元素的向量:第一个是数字,第二个是树列表或零

以下clojure数据结构就是一个示例:

(def tree '[9 ([4 nil]
               [6 nil]
               [2 ([55 nil]
                   [22 nil]
                   [3 ([5 nil])])]
               [67 ([44 nil])])])
该结构应转换为所有可能向下连接的列表,可以从任何节点到其子节点。连接应表示为向量,其中包含父节点的值,后跟子节点的值。顺序并不重要:

(def result '([9 4]
              [9 6]
              [9 2]
              [2 55]
              [2 22]
              [2 3]
              [3 5]
              [9 67]
              [67 44])
我提出了这个解决方案:

(defn get-connections [[x xs]]
  (concat (map #(vector x (first %)) xs)
          (mapcat get-connections xs)))
事实上:

(= (sort result)
   (sort (get-connections tree)))
;; true
但是,有没有更好的方法只使用普通clojure来实现这一点?在这种方法中,我将遍历每个节点的子节点两次,应该避免这种情况。在这种特殊情况下,尾部递归是不必要的,所以简单的递归版本就可以了


此外,我想知道哪些更高层次的抽象可以用来解决这个问题。拉链或Clojure/步行怎么样?最后:ClojureScript中也可以使用哪些技术?

您可以尝试列表理解+树序列的组合:

user> (for [[value children] (tree-seq coll? second tree)
            [child-value] children]
        [value child-value])

;;=> ([9 4] [9 6] [9 2] [9 67] [2 55] [2 22] [2 3] [3 5] [67 44])
这应该在cljs中提供

据我所知,Zipppers和clojure.walk在clojurescript中都可用,但事实上,您不需要它们来完成这项琐碎的任务。我想
tree-seq
是相当惯用的

对于双遍历,您可以很容易地将其重新排列为如下所示的单个遍历:

(defn get-connections [[x xs]]
  (mapcat #(cons [x (first %)] (get-connections %)) xs))

user> (get-connections tree)
;;=> ([9 4] [9 6] [9 2] [2 55] [2 22] [2 3] [3 5] [9 67] [67 44])
然后,您可以添加懒惰,以使此解决方案真正地道:

(defn get-connections [[x xs]]
  (mapcat #(lazy-seq (cons [x (first %)] (get-connections %))) xs))

我没有时间早些检查这个答案。感谢您提供的伟大解决方案。他们做得很好。