A walk is recursive and does not contain a battery argument, so you had to resort to updating atoms.
A zipper is iterative, so you can transfer other information without breaking the functional template.
Natural rewinding in depth is a preliminary detour, but you are after the post-order, so this requires a little extra work.
Here is a workaround after a lightning workout:
(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))))))))
And a test case:
(dfs-post-order-traversal (z/seq-zip '((ab) (cd)))) => [ab (ab) cd (cd) ((ab) (cd))]
Now, to complete your request, we need to match the locations of the trees with their indices:
(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] [(mn) n (if (branch? n) (map m (children n)) (list))]))) (dfs-post-order-indexing seq? identity '((ab) (cd))) => ([0 a ()] [1 b ()] [2 (ab) (0 1)] [3 c ()] [4 d ()] [5 (cd) (3 4)] [6 ((ab) (cd)) (2 5)])
Something more exotic:
(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)])
A. Webb
source share