将两个 clojure.walk/postwalk 调用合并为一个

Combining Two clojure.walk/postwalk Calls Into One

我有以下数据:

 28 (def example {"1ce9b863-5681-4660-85e7-fbd0cc184aed"
 29               {"58825b50-23bc-4204-8f8d-c9a9d3ac8beb" {},
 30                "4b1763f9-8380-4507-9a8f-5c86878e49a9" {},
 31                "160f34ac-68b9-4c8e-930b-1ab6df895df4" {}},                                                                                
 32               "6378daf6-3b7f-4cf4-8156-a50cf5f7b6ef"
 33               {"669fe949-057f-43c0-af7b-ff39594a183d" {},
 34                "73d2a203-e3c1-4d2f-aaf8-a9f2e870792b" {},
 35                "8c9c57a0-d20d-4474-9afb-c9d17df83a91" {},
 36                "94bf72cb-01cd-4430-b669-b2e954b5639b"
 37                {"ba96a425-a3f0-4ce5-8c19-6ea9add14013" {},
 38                 "1ceff8fe-a0a8-46ad-81a8-d13fb837aaf6" {}}}})
 39 
 40 (def titles (list {:id "58825b50-23bc-4204-8f8d-c9a9d3ac8beb", :title "Low"}
 41                   {:id "4b1763f9-8380-4507-9a8f-5c86878e49a9", :title "Medium"}
 42                   {:id "160f34ac-68b9-4c8e-930b-1ab6df895df4", :title "High"}
 43                   {:id "1ce9b863-5681-4660-85e7-fbd0cc184aed", :title "Priority"}
 44                   {:id "1ceff8fe-a0a8-46ad-81a8-d13fb837aaf6", :title "Drafting"}
 45                   {:id "ba96a425-a3f0-4ce5-8c19-6ea9add14013", :title "Brainstorm"}
 46                   {:id "94bf72cb-01cd-4430-b669-b2e954b5639b", :title "Planning"}
 47                   {:id "8c9c57a0-d20d-4474-9afb-c9d17df83a91", :title "Testing"}
 48                   {:id "73d2a203-e3c1-4d2f-aaf8-a9f2e870792b", :title "Implementation"}
 49                   {:id "669fe949-057f-43c0-af7b-ff39594a183d", :title "Completed"}
 50                   {:id "6378daf6-3b7f-4cf4-8156-a50cf5f7b6ef", :title "Status"}))

我正在尝试使用 sablono/hiccup 样式语法将此数据转换为嵌套列表结构。目前我有以下工作解决方案:

 52 (defn id->title [x]
 53   (let [tuples (map (fn [x] [(:id x) (:title x)]) titles)]
 54     (first (for [[k t] tuples :when (= k x)] t))))               

 57 (->> example
 58      (clojure.walk/postwalk
 59        (fn [x] (if-not (string? x)
 60                  (vec x) x)))
 61      (clojure.walk/postwalk
 62        (fn [x] (if (vector? x)
 63                  (if (vector? (first x))
 64                    (vec (cons :ul x))
 65                    (vec (cons :li x)))
 66                  (id->title x)))))

这导致:

[:ul  
 [:li "Priority"
  [:ul 
    [:li "Low" [:li]] 
    [:li "Medium" [:li]] 
    [:li "High" [:li]]]]
 [:li "Status"
  [:ul
   [:li "Completed" [:li]]
   [:li "Implementation" [:li]]
   [:li "Testing" [:li]]
   [:li "Planning"
    [:ul 
      [:li "Brainstorm" [:li]] 
      [:li "Drafting" [:li]]]]]]]

我怎样才能将其简化为一次步行?我也在考虑用地图替换 titles 以进行高效查找(我正在从 Neo4j 中提取所有这些数据)。

根据您提供的数据,您可以尝试如下操作:

(defn id->title [x]
  (->> titles (filter #(= (:id %) x)) first :title))

(defn format-data [structure]
  (clojure.walk/postwalk
    (fn [x]
      (if (map? x)
        (into [:ul] (map (fn [[k v]]
                           (if (= v [:ul])
                             [:li (id->title k)]
                             [:li (id->title k) v]))
                         (seq x)))
        x))
  structure))

在 postwalk 期间,这会将每个映射转换为表示无序列表的向量(即使是空映射),并将每个键值对转换为表示列表项的向量。 (if (= v [:ul]) ...) 确保从最终结构中删除空的无序列表。

运行 (pprint (format-data example)) 给出以下结果:

[:ul
 [:li "Priority" [:ul [:li "Low"] [:li "Medium"] [:li "High"]]]
 [:li
  "Status"
  [:ul
   [:li "Completed"]
   [:li "Implementation"]
   [:li "Testing"]
   [:li "Planning" [:ul [:li "Brainstorm"] [:li "Drafting"]]]]]]