Clojure 如何将seq转换为树
我有一系列地图,比如下面的coll。我想把它放在树上。每个映射都有一个名为:parent的键,它是父映射的:id。有什么关于我怎么做的提示吗Clojure 如何将seq转换为树,clojure,Clojure,我有一系列地图,比如下面的coll。我想把它放在树上。每个映射都有一个名为:parent的键,它是父映射的:id。有什么关于我怎么做的提示吗 (def coll [{:id 1} {:id 2 :parent 1} {:id 3 :parent 1} {:id 4 :parent 2} {:id 5 :parent 4} {:id 6 :parent 5} {:id 7 :
(def coll [{:id 1}
{:id 2 :parent 1}
{:id 3 :parent 1}
{:id 4 :parent 2}
{:id 5 :parent 4}
{:id 6 :parent 5}
{:id 7 :parent 5}
{:id 8 :parent 5}
{:id 9 :parent 7}])
这里有一个使用序列理解的小解决方案。希望它是可读的,但它肯定不会因为性能而赢得任何奖项,因为它会在递归的每个级别重新过滤列表。我想有一个非常高效的基于reduce的解决方案是可能的,但我仍然掌握了写这些的窍门——希望其他人会发布一个:) 注意-我已经返回了每个节点的整个地图,因为我不确定您希望树看起来像什么
(defn make-tree
([coll] (let [root (first (remove :parent coll))]
{:node root :children (make-tree root coll)}))
([root coll]
(for [x coll :when (= (:parent x) (:id root))]
{:node x :children (make-tree x coll)})))
(pprint (make-tree coll))
{:node {:id 1},
:children
({:node {:parent 1, :id 2},
:children
({:node {:parent 2, :id 4},
:children
({:node {:parent 4, :id 5},
:children
({:node {:parent 5, :id 6}, :children ()}
{:node {:parent 5, :id 7},
:children ({:node {:parent 7, :id 9}, :children ()})}
{:node {:parent 5, :id 8}, :children ()})})})}
{:node {:parent 1, :id 3}, :children ()})}
如果它像树一样行走
(require '[clojure.zip :as z])
(defn create-zipper [s]
(let [g (group-by :parent s)]
(z/zipper g #(map :id (g %)) nil (-> nil g first :id))))
(def t (create-zipper coll)) ; using the coll defined in the OP
(-> t z/root)
;=> 1
(-> t z/children)
;=> (2 3)
(-> t z/next z/children)
;=> (4)
请注意,您可以使用#(g(%:id))
作为子节点,使用(first(g nil))
作为根节点来保留原始节点的格式(而不仅仅是返回id号)
如果需要,可以使用来构建树的另一个表示形式。是否需要此转换来实现持久性/序列化?否则,您应该在大多数情况下尝试进行相反的转换。