Clojure解析嵌套向量

时间:2018-11-19 00:02:18

标签: clojure tree zipper

我希望将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,但看不出来!

2 个答案:

答案 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/nextloop遍历树:树中的当前位置和正在构建的地图。 / 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