Clojure中的树遍历
考虑一棵树,它由以下递归定义定义: 树应该是两个元素的向量:第一个是数字,第二个是树列表或零 以下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])])]) 该结构应转换为所有可
(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))
我没有时间早些检查这个答案。感谢您提供的伟大解决方案。他们做得很好。