爲了測試,我須要相似下面的數據:app
{:id 55 :parent_id nil} {:id 104 :parent_id 55}
最終函數能夠指定層數和每一個分支的個數,好比2層10個,總共110,3層10個1110,4層10個11110等等。函數
我整整花了2個白天時間,總算寫了出來,固然中間順帶練習了一下macro。有兩個版本,一個是macro版本,一個是iterate版本,固然後者應該是正解。測試
爲了減小macro代碼的複雜度,先寫了一個子函數。spa
(defn- create-children [parentv n] (flatten (map (fn [pnd] (take n (map (fn [id] {:id id, :parent_id (:id pnd)}) (repeatedly get-next)))) parentv)))
中間的map生成一個條目的n個兒子,外網的map根據傳遞過來的父節點的集合,對每一個父節點生成n個兒子。生成:scala
( (10個兒子) (10個兒子) (10個兒子)),這樣的結構。最後flatten扁平化成一個集合。rest
接下來是函數的實現:code
macro版本:get
(defmacro tree-items [lev n] (let [llls (let [levs (map #(symbol (str "i" %)) (rest (range lev))) levs1 (map #(symbol (str "i" %)) (drop-last (range lev))) ctpl '(create-children x y) tpl-seq (map #(vector %1 (template/apply-template '[x y] ctpl [%2 n])) levs levs1)] (vec (apply concat tpl-seq))) lresult (vec (map #(symbol (str "i" %)) (rest (range lev)))) scaffold (template/apply-template '[x llls lresult] '(let [i0 (take x (map #(assoc {:parent_id nil} :id %) (repeatedly get-next))) levels (let llls lresult)] (flatten [i0 levels])) [n llls lresult])]
所謂macro,就是用程序寫程序,執行macro的結果是程序代碼,而後再執行生成的代碼。能夠用macroexpand來查看生成的程序的結果。it
(let* [i0 (take 10 (map (fn* [p1__60273#] (assoc {:parent_id nil} :id p1__60273#)) (repeatedly get-next))) levels (let [i1 (create-children i0 10) i2 (create-children i1 10) i3 (create-children i2 10) i4 (create-children i3 10)] [i1 i2 i3 i4])] (flatten [i0 levels]))
固然寫macro比較殺腦細胞。ast
iterate版本:
(defn tree-items-i [lev n] (let [lev (dec lev) rootn (take n (map #(assoc {:parent_id nil} :id %) (repeatedly get-next)))] (flatten (take lev (iterate #(create-children % n) rootn)))))
代碼明顯簡單多了。
總結:
clojure的一些產生無限序列的函數或者macro須要多加練習才能領悟。
有時候當局者迷,也許你看了這個代碼會以爲很可笑,由於你知道更方便的寫法。若是這樣,請告訴我。