给定一个编码为一组嵌套列表的树(例如,(+ 2 (+ 2 1) (+ 1 3 2))
),Clojure中是否存在随机遍历树的已知算法,在单个节点上应用参数化提供的函数,概率相等'着陆'在任何节点?注意:转换在单个节点转换后终止。
我希望算法的行为如下:
(def tree '(1 (1 (1 1 1) 1) 1))
(stochastic-tree-f-app inc tree) => (1 (1 (1 2 1) 1) 1)
(stochastic-tree-f-app inc tree) => (1 (1 (1 1 2) 1) 1)
(stochastic-tree-f-app inc tree) => (2 (1 (1 1 1) 1) 1)
(stochastic-tree-f-app inc tree) => (1 (1 (1 1 1) 1) 2)
(stochastic-tree-f-app dec tree) => (1 (1 (1 1 1) 0) 1)
答案 0 :(得分:4)
使用clojure.zip:
(require '[clojure.zip :as z])
(defn stochastic-tree-f-app [f tree]
(let [zp (z/zipper list? seq (fn [_ c] c) tree)
nodes (->> (iterate z/next zp)
(take-while (complement z/end?))
(filter (comp integer? z/node))
(into []))]
(-> (rand-nth nodes)
(z/edit f)
z/root)))
答案 1 :(得分:1)
如果最后一个要求可以解除,你可以简单地使用clojure.walk(即...转换在单个节点转换后终止)。或者使用拉链向下走节点,然后通过编辑终止。使用clojure.walk:
(use 'clojure.walk)
(def tree '(1 (1 (1 1 1) 1) 1))
(defn stochastic-tree-f-app [f tree]
(let [cnt (atom 0)
_ (postwalk #(if (integer? %) (swap! cnt inc)) tree)
idx (rand-int @cnt)]
(reset! cnt 0)
(postwalk #(if (and (integer? %) (= idx (swap! cnt inc)))
(f %)
%)
tree)))
user> (stochastic-tree-f-app inc tree)
(2 (1 (1 1 1) 1) 1)
user> (stochastic-tree-f-app inc tree)
(1 (1 (1 1 1) 2) 1)