使用clojure.zip进行Postorder树遍历以编辑节点

使用clojure.zip进行Postorder树遍历以编辑节点,clojure,tree,traversal,zipper,Clojure,Tree,Traversal,Zipper,我有一个用嵌套向量表示的树。我想对树的索引进行一个泛化,显示每个节点的索引,如下所示 (visit 42); => [0 42] (visit [6 7]); => [0 ; [[0 6] ; [1 7]]] 天真的实现将直接使用clojure.zip() 但是使用clojure.zip/next重复执行一个前序遍历,在这种情况下会产生一个无限循环(未访问的节点将无限地连接到[:found]向量中)。另一种

我有一个用嵌套向量表示的树。我想对树的
索引
进行一个泛化,显示每个节点的索引,如下所示

(visit 42); => [0 42]
(visit [6 7]); => [0
              ;     [[0 6] 
              ;      [1 7]]]
天真的实现将直接使用clojure.zip()

但是使用
clojure.zip/next
重复执行一个前序遍历,在这种情况下会产生一个无限循环(未访问的节点将
无限地连接到
[:found]
向量中)。另一种方法是使用
clojure.walk/postwark
,但它不提供结构信息,例如索引


您将如何实现这一点?是否有一个zip的
后序下一步
可以立即解决问题?

我不确定是否理解您的意图,但示例向我表明,分配给节点的索引对应于其左兄弟节点的数量(因为在第二个示例中,根节点和
6
子节点都被标记为
0
)。更新:显然,第一次我只是误读了
visit
示例——它使意图足够清楚……幸运的是,现在我正确地阅读了它,我觉得下面的答案是正确的

如果这是正确的,这是一个基于
clojure.walk/postwark
的解决方案:

(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]
更新:使用
映射索引
的简单解决方案(在1.2中提供;在1.1中使用
映射
+
clojure.contrib.seq utils/index
):

user> (index-vec-tree [6 7])
[0 [[0 6] [1 7]]]
user> (index-vec-tree 42)
[0 42]
(defn index-vec-tree [vt]
  (letfn [(iter [i vt] [i (if (vector? vt)
                                (vec (map-indexed iter vt))
                                vt)])]
    (iter 0 vt)))