gpt4 book ai didi

clojure - 使用 clojure.walk 深度优先索引任何 Clojure 表单

转载 作者:行者123 更新时间:2023-12-04 07:04:54 25 4
gpt4 key购买 nike

给定以下树(或 Clojure 中的任何其他形式,包括映射和向量):

'( (a b) (c d) )

我想在 Clojure 中生成一个映射,该映射根据整个表单的深度优先遍历对每个子表单进行索引,并提供表单子(monad)项(如果有)索引的向量(或列表)。
0 -> a []
1 -> b []
2 -> (a b) [0 1]
3 -> c []
4 -> d []
5 -> (c d) [3 4]
6 -> ( (a b) (c d) ) [2 5]

到目前为止,我只设法使用 clojure.walk 生成第一部分(索引子表单),但我对如何生成子索引也感到困惑。我的代码附加在最后并产生:
user=> (depthFirstIndexing '( (a b) (c d) ))
{6 ((a b) (c d)), 5 (c d), 4 d, 3 c, 2 (a b), 1 b, 0 a}

因此,子表单的索引是根据深度优先遍历正确生成的,但我不知道如何获得每个子表单的子表单的索引。我尝试使用 zippers 模块,但看不到如何执行深度优先遍历来收集索引。

中途代码
(use 'clojure.walk)
(defn depthFirstIndexing [aform]
(let [counter (atom -1)
idxToSubform (atom {})
]
(postwalk (fn [x]
(def idx (swap! counter inc))
(swap! idxToSubform assoc idx x)
x)
aform)
@idxToSubform))

最佳答案

一个 walk是递归的并且不提供累加器参数,这就是为什么你不得不求助于更新原子。

一个 zipper是迭代的,因此您可以在不破坏功能模式的情况下携带其他信息。

自然的深度优先遍历是前序遍历,但是你是在后序遍历之后,所以这需要一些额外的工作。

这是使用 zippers 的后序遍历:

(require '[clojure.zip :as z])

(defn dfs-post-order-traversal [zipper]
(loop [loc zipper, a []]
(cond
(z/end? loc)
(conj a (z/node loc))
(z/branch? loc)
(recur (z/next loc) a)
:else
(recur
(z/next loc)
(into
(conj a (z/node loc))
(reverse
(drop
((fnil count [nil]) (z/path (z/next loc)))
(z/path loc))))))))

和测试用例:
(dfs-post-order-traversal (z/seq-zip '((a b) (c d))))
=> [a b (a b) c d (c d) ((a b) (c d))]

现在要完成您的请求,我们需要将树位置映射回它们的索引:
(defn dfs-post-order-indexing [branch? children root]
(let [pot (dfs-post-order-traversal (z/zipper branch? children conj root))
m (zipmap pot (range))]
(for [n pot] [(m n) n (if (branch? n) (map m (children n)) (list))])))

(dfs-post-order-indexing seq? identity '((a b) (c d)))
=> ([0 a ()]
[1 b ()]
[2 (a b) (0 1)]
[3 c ()]
[4 d ()]
[5 (c d) (3 4)]
[6 ((a b) (c d)) (2 5)])

更奇特的东西:
(dfs-post-order-indexing coll? seq [{:a :b :c :d} :e [:f [:g '(:h :i)]]])
=> ([0 :a ()]
[1 :b ()]
[2 [:a :b] (0 1)]
[3 :c ()]
[4 :d ()]
[5 [:c :d] (3 4)]
[6 {:a :b, :c :d} (2 5)]
[7 :e ()]
[8 :f ()]
[9 :g ()]
[10 :h ()]
[11 :i ()]
[12 (:h :i) (10 11)]
[13 [:g (:h :i)] (9 12)]
[14 [:f [:g (:h :i)]] (8 13)]
[15 [{:a :b, :c :d} :e [:f [:g (:h :i)]]] (6 7 14)])

关于clojure - 使用 clojure.walk 深度优先索引任何 Clojure 表单,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14865213/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com