clojure產生具備parent-id的樣例數據。(懇請提供更好的思路)

爲了測試,我須要相似下面的數據: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須要多加練習才能領悟。

有時候當局者迷,也許你看了這個代碼會以爲很可笑,由於你知道更方便的寫法。若是這樣,請告訴我。

相關文章
相關標籤/搜索