首页 > 代码库 > clojure产生具有parent-id的样例数据。(恳请提供更好的思路)

clojure产生具有parent-id的样例数据。(恳请提供更好的思路)

为了测试,我需要类似下面的数据:

{:id 55 :parent_id nil} {:id 104 :parent_id 55}

最终函数可以指定层数和每个分支的个数,比如2层10个,总共110,3层10个1110,4层10个11110等等。

我整整花了2个白天时间,总算写了出来,当然中间顺带练习了一下macro。有两个版本,一个是macro版本,一个是iterate版本,当然后者应该是正解。

为了减少macro代码的复杂度,先写了一个子函数。

(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个儿子。生成:

( (10个儿子) (10个儿子)  (10个儿子)),这样的结构。最后flatten扁平化成一个集合。

接下来是函数的实现:

macro版本:

(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来查看生成的程序的结果。

(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比较杀脑细胞。

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需要多加练习才能领悟。

有时候当局者迷,也许你看了这个代码会觉得很好笑,因为你知道更方便的写法。如果这样,请告诉我。

clojure产生具有parent-id的样例数据。(恳请提供更好的思路)