移动分区依据的拆分 "back by one"

Moving partition-by's splits "back by one"

我正在 CLJS 中解析一些 Hiccup,目的是获取 :h2:h3 元素并将它们转换为嵌套的 :ul:li 树.

我的起点是平面矢量,例如:

[[:h2 {} "Foo"] [:h2 {} "Bar"] [:h3 {} "Child1"] [:h2 {} "Baz"]]

如果我只是映射这些并将 (first el) 替换为 [:li],我有一个简单的列表。但我想得到类似的东西:

[[:li "Foo"] [:li "Bar"] [:ul [:li "Child1"]] [:li "Baz"]]

如果我调用 (partition-by #(= :h2 (first %)) my-vec),我会得到一些几乎有用的东西:

(([:h2 {} "Foo"] [:h2 {} "Bar"]) ([:h3 {} "Child1"]) ([:h2 {} "Baz"]))

分区发生在谓词 #(= :h2 (first %)) 发生变化时,(这是文档所说的)。

如何获得我正在寻找的行为?

这是一种方法:

(def data [
    [:h2 {} "Foo"]
    [:h2 {} "Bar"]
    [:h3 {} "Child1"]
    [:h2 {} "Baz"] ] )

(defn formatter [elem]
  (condp = (first elem)
    :h2           [:li (last elem)]
    :h3      [:ul [:li (last elem)]]
    ))

(newline) (println :data data)
(newline) (println :result (mapv formatter data))

结果

:data [[:h2 {} Foo] [:h2 {} Bar] [:h3 {} Child1] [:h2 {} Baz]]

:result [[:li Foo] [:li Bar] [:ul [:li Child1]] [:li Baz]]

更新:

像这样重写以将所有 :h3 项目合而为一 :ul

(def data [
    [:h2 {} "Foo"]
    [:h3 {} "Child1"]
    [:h2 {} "Bar"]
    [:h3 {} "Child2"]
    [:h3 {} "Child3"]
    [:h2 {} "Baz"] ] )

(defn h2? [elem]
  (= :h2 (first elem)))

(defn ->li [elem]
  [:li (last elem)])

(defn fmt [data]
  (let [h2 (filter h2? data)
        h3 (filter #(not (h2? %)) data)
        result  (conj (mapv ->li h2)
                  (apply vector :ul (mapv ->li h3))) ]
        result ))

(newline) (println :data data)
(newline) (println :result (fmt data))

结果

:data [[:h2 {} Foo] [:h3 {} Child1] [:h2 {} Bar] [:h3 {} Child2] [:h3 {} Child3] [:h2 {} Baz]]

:result [[:li Foo] [:li Bar] [:li Baz] [:ul [:li Child1] [:li Child2] [:li Child3]]]

这是一个可以完成工作的答案,但非常不优雅,因为它在必要时实质上改变了 reduce 调用中的最后一个元素:

(defn listify-element [element]
  "Replaces element type with :li."
  (vec (concat [:li (last element))]))

(defn listify-headings [headings-list]
  "Takes subitems (in :h2 :h3) and creates sub :uls out of the :h3 lists."
  (vec
   (concat
    [:ul]
    (map-indexed
     (fn [ind headings]
       (if (= 0 (mod ind 2))
         (map listify-element headings)
         (vec (concat [:ul] (map listify-element headings)))))
     (partition-by #(= :h2 (first %)) headings-list)))))

(defn nest-listified-headings [vector-list]
  "Nests sub-:uls inside their preceding :lis."
  (vec (concat [:ul]
          (reduce
           (fn [acc el] (if (= (first el) :ul)
                          (conj (pop (vec acc)) (conj (last acc) el))
                          (concat acc el)))
           vector-list))))

生产:

(nest-listified-headings 
  (listify-headings [[:h2 "Foo"] [:h2 "Bar"] [:h3 "Baz"] [:h3 "Bat"]])

[:ul [:li "Foo"] 
     [:li "Bar" 
     [:ul 
       [:li "Baz"] 
       [:li "Bat"]]]]