[英]Clojure: transform collection into multiple trees
因此,我有一個用於注釋的數據庫表,並且學習了如何使用WITH RECURSIVE
以樹的形式返回主題的所有注釋。 但是,由於它是SQL,因此只是作為列表返回。
當我執行查詢時,這些是我取回的結果(級別不是表上的列,它是由查詢在收集結果時計算的):
[
{
:id "1"
:parent_id nil,
:content "This is another top-level comment",
:level "1",
:rating 0,
}
{
:id "2"
:parent_id "1",
:content "What a comment!",
:level "1 -> 2",
:rating 0,
}
{
:id "4"
:parent_id "2",
:content "Trying to see how trees work",
:level "1 -> 2 -> 4",
:rating 0,
}
{
:id "3"
:parent_id "2",
:content "No idea how this will turn out",
:level "1 -> 2 -> 3",
:rating 0,
}
{
:id "5"
:parent_id nil,
:content "This is a top-level comment",
:level "5",
:rating 0,
}
{
:id "9"
:parent_id "5",
:content "This is yet another testing comment",
:level "5 -> 9",
:rating 0,
}
{
:id "8"
:parent_id "7",
:content "It sure is!",
:level "5 -> 7 -> 8",
:rating 0,
}
{
:id "7"
:parent_id "5",
:content "This!",
:level "5 -> 7",
:rating 0,
}
{
:id "6"
:parent_id "5",
:content "Hey look at me",
:level "5 -> 6",
:rating 0,
}
]
我想弄清楚的是如何轉動多棵樹,這樣我最終得到如下結果:
1 'This is another top-level comment'
↳ 2 'What a comment!'
↳ 4 'Trying to see how trees work'
↳ 3 'No idea how this will turn out'
5 'This is a top-level comment'
↳ 9 'This is yet another testing comment'
↳ 7 'This!'
↳ 8 'It sure is!'
↳ 6 'Hey look at me'
使用此功能只會使我得到第一棵樹(根節點為id 1的樹):
(defn make-tree
([coll] (let [root (first (remove :parent coll))]
{:node root :children (make-tree root coll)}))
([root coll]
(for [x coll :when (= (:parent_id x) (:id root))]
{:node x :children (make-tree x coll)})))
關於如何修改該功能或更改所傳遞的內容的任何想法或提示,以便最終獲得多棵樹?
您可以定義一個make-trees函數:
(defn make-trees [id coll]
(map
(fn [node] {:node node :children (make-trees (node :id) coll)})
(filter #(= (% :parent_id) id) coll)))
這樣稱呼:
(make-trees nil YOUR_COLL)
如果您可以依靠:level
條目,那么它可以用作與assoc-in
一起使用的鍵序列的來源。 然后,您可以使用專用的根節點執行方法@coredump,只需使用reduce
和在assoc-in
上構建的小lambda即可:
(defn- key-seq [comment]
(->> comment
:level
(re-seq (re-pattern "\\d+"))
(interpose :children)))
(defn list->forest [comments]
(vals (reduce (fn [root comment]
(assoc-in root (key-seq comment) {:node comment :children {}}))
{}
comments)))
在這里,我在reduce
的結果上使用vals
來再次丟棄外部根映射,但這是可選的。
如果要在其上使用的實際數據實際上在:level
具有UUID,則需要使用更合適的正則表達式。 上面將把十進制數字的任何部分都當作ID。 使用這些答案,我們可以改為收集:level
字符串中的所有UUID。
我用一些隨機的UUID代替了您給出的數字來重新整理了示例數據 。 然后,使用以上鏈接中的Gajus Kuizinas的正則表達式進行了以下重新定義:
(ns comment-forest
(:require [clojure.walk :refer [postwalk]]
[clojure.pprint :refer [pprint]])
(:import java.util.UUID))
(defn- key-seq [comment]
(->> comment
:level
(re-seq (re-pattern "[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-4[a-fA-F0-9]{3}-[89aAbB][a-fA-F0-9]{3}-[a-fA-F0-9]{12}"))
(map #(UUID/fromString %))
(interpose :children)))
;;This is just to print the trees with less unnecessary detail
(defn- prune [value]
(if
(or
(not (map? value))
(every? (partial contains? value) [:node :children])
(every? #(= UUID (type %)) (keys value)))
value
(select-keys value [:id :content])))
(pprint (map (partial postwalk prune) (list->forest querylist)))
獲得輸出
({:node
{:content "This is a top-level comment",
:id "ee9a2671-b47e-40ef-994f-a7b0fa81d717"},
:children
{#uuid "f28a159c-de66-4712-9cb8-e1841afeebf6"
{:node
{:content "Hey look at me",
:id "f28a159c-de66-4712-9cb8-e1841afeebf6"},
:children {}},
#uuid "d3fccc58-5e59-486d-b784-c54f0e4698b1"
{:node
{:content "This!", :id "d3fccc58-5e59-486d-b784-c54f0e4698b1"},
:children
{#uuid "e6387f7d-4f29-42c9-a386-7f799341f48f"
{:node
{:content "It sure is!",
:id "e6387f7d-4f29-42c9-a386-7f799341f48f"},
:children {}}}},
#uuid "3de27950-7340-49d1-a28e-54ad2e4ea0f1"
{:node
{:content "This is yet another testing comment",
:id "3de27950-7340-49d1-a28e-54ad2e4ea0f1"},
:children {}}}}
{:node
{:content "This is another top-level comment",
:id "fdc8a8b9-19c7-4fad-963d-2c2ca0bcbe8a"},
:children
{#uuid "b17bc5b8-9968-48ce-8ff3-83c8123cd327"
{:node
{:content "What a comment!",
:id "b17bc5b8-9968-48ce-8ff3-83c8123cd327"},
:children
{#uuid "1cee5390-e810-49b7-ad10-098bfbe03ab2"
{:node
{:content "No idea how this will turn out",
:id "1cee5390-e810-49b7-ad10-098bfbe03ab2"},
:children {}}}}}})
原來@coredump有正確的主意。 通過使頂級注釋具有其parent-id作為主題,那么我可以使用clojure.zip/zipper輕松構建一棵樹。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.