我希望将clojure树形结构转换为其具有相关性的地图
例如,输入如下:
[{:value "A"}
[{:value "B"}
[{:value "C"} {:value "D"}]
[{:value "E"} [{:value "F"}]]]]
等同于:
:A
:B
:C
:D
:E
:F
输出:
{:A [:B :E] :B [:C :D] :C [] :D [] :E [:F] :F}
我看了看tree-seq和zippers,但看不出来!
答案 0 :(得分:1)
这是一种在使用拉链遍历树时构建所需地图的方法。首先,让我们简化输入树以匹配您的输出格式(:value
个字符串的映射→关键字):
(def tree
[{:value "A"}
[{:value "B"} [{:value "C"} {:value "D"}]
{:value "E"} [{:value "F"}]]])
(def simpler-tree
(clojure.walk/postwalk
#(if (map? %) (keyword (:value %)) %)
tree))
;; [:A [:B [:C :D] :E [:F]]]
然后,您可以使用两个loop
绑定使用recur
/ clojure.zip/next
和loop
遍历树:树中的当前位置和正在构建的地图。 / p>
(loop [loc (z/vector-zip simpler-tree)
deps {}]
(if (z/end? loc)
deps ;; return map when end is reached
(recur
(z/next loc) ;; advance through tree
(if (z/branch? loc)
;; for (non-root) branches, add top-level key with direct descendants
(if-let [parent (some-> (z/prev loc) z/node)]
(assoc deps parent (filterv keyword? (z/children loc)))
deps)
;; otherwise add top-level key with no direct descendants
(assoc deps (z/node loc) [])))))
=> {:A [:B :E], :B [:C :D], :C [], :D [], :E [:F], :F []}
答案 1 :(得分:0)
使用tupelo.forest库很容易做到。我重新格式化了您的源数据,使其适合打ic语法:
(dotest
(let [relationhip-data-hiccup [:A
[:B
[:C]
[:D]]
[:E
[:F]]]
expected-result {:A [:B :E]
:B [:C :D]
:C []
:D []
:E [:F]
:F []} ]
(with-debug-hid
(with-forest (new-forest)
(let [root-hid (tf/add-tree-hiccup relationhip-data-hiccup)
result (apply glue (sorted-map)
(forv [hid (all-hids)]
(let [parent-tag (grab :tag (hid->node hid))
kid-tags (forv [kid-hid (hid->kids hid)]
(let [kid-tag (grab :tag (hid->node kid-hid))]
kid-tag))]
{parent-tag kid-tags})))]
(is= (format-paths (find-paths root-hid [:A]))
[[{:tag :A}
[{:tag :B} [{:tag :C}] [{:tag :D}]]
[{:tag :E} [{:tag :F}]]]])
(is= result expected-result ))))))
API文档are here。项目自述文件(正在进行中)is here。 2017 Clojure Conj is here中的视频。
您可以看到上面的实时代码in the project repo。