我有一个表示为嵌套向量的树。我想对树进行indexed
的推广,显示每个节点的索引,如下所示,
(visit 42); => [0 42]
(visit [6 7]); => [0
; [[0 6]
; [1 7]]]
天真的实现将直接使用clojure.zip(as already asked here)
(defn visit [tree]
(loop [loc (vector-zip tree)]
(if (end? loc)
(root loc)
(recur
(next (edit loc #(conj
[(count (lefts loc))]
%)))))))
但是clojure.zip/next
重复执行前序遍历,在这种情况下导致无限循环(未访问的节点无限地将conj
编辑到[:found]
向量中。另一种方法是使用clojure.walk/postwalk
,但它不提供结构信息,例如索引。
你会如何实现这个?是否有postorder-next
的拉链可以立即解决它?
答案 0 :(得分:4)
我不确定我是否理解你要做的事情,但是这些例子告诉我,分配给节点的索引对应于他们的左兄弟的数量(因为在第二个例子中都是根节点)并且6
孩子标有0
)。 更新:显然我只是第一次误读visit
示例 - 它使意图足够清楚......幸运的是,现在我正确阅读了它,在我看来,下面的答案是正确的。< / em>的
如果这是正确的,这是一个基于clojure.walk/postwalk
的解决方案:
(defn index-vec-tree [vt]
[0 (walk/postwalk
(fn [node]
(if-not (vector? node)
node
(vec (map-indexed vector node))))
vt)])
通过给出的例子:
user> (index-vec-tree [6 7])
[0 [[0 6] [1 7]]]
user> (index-vec-tree 42)
[0 42]
更新:使用map-indexed
的简单解决方案(在1.2中提供;在1.1中使用map
+ clojure.contrib.seq-utils/indexed
):
(defn index-vec-tree [vt]
(letfn [(iter [i vt] [i (if (vector? vt)
(vec (map-indexed iter vt))
vt)])]
(iter 0 vt)))