次のベクトルがあります [-1 1 2 -1 3 0 -1 2 -1 4 0 3 0 0]
木を表すもの[[1 2 [3] [2 [4] 3]]]
ここで、-1 は新しいブランチを開始し、0 はそれを終了します。元のベクターを使用可能なツリーのような clojure 構造 (ネストされたベクター、ネストされたマップ) に変換するにはどうすればよいですか? 私clojure.zip/zipper
はそれを行うかもしれないと思いますが、それらの関数引数を構築する方法がわかりません。
ジッパーはこれに適したツールです。
(require '[clojure.zip :as zip])
(def in [-1 1 2 -1 3 0 -1 2 -1 4 0 3 0 0])
(def out [[1 2 [3] [2 [4] 3]]])
(defn deepen [steps]
(->> steps
(reduce (fn [loc step]
(case step
-1 (-> loc
(zip/append-child [])
(zip/down)
(zip/rightmost))
0 (zip/up loc)
(zip/append-child loc step)))
(zip/vector-zip []))
(zip/root)))
(assert (= (deepen in) out))
どういうわけか、これは不正行為のように感じます:
[(read-string
(clojure.string/join " "
(replace {-1 "[" 0 "]"}
[-1 1 2 -1 3 0 -1 2 -1 4 0 3 0 0])))]
これは再帰を使えばそれほど難しくありません:
(defn numbers->tree [xs]
(letfn [(step [xs]
(loop [ret [], remainder xs]
(if (empty? remainder)
[ret remainder]
(let [x (first remainder)]
(case x
0 [ret (next remainder)]
-1 (let [[ret' remainder'] (step (next remainder))]
(recur (conj ret ret'), remainder'))
(recur (conj ret x) (next remainder)))))))]
(first (step xs))))
アイデアはstep
、サブツリーを見つけ、そのツリーと、処理が残っている数字を返す関数 ( ) を持つことです。ほとんどの入力に対して( を介してloop
) 反復処理を行い、 に遭遇すると、それ自体の再帰的なインスタンスを開始します-1
。唯一のトリッキーな部分はremainder
、途中のリストを続行するのではなく、これらの再帰呼び出しから返されたを使用することを確認することです。