【问题标题】:Moving partition-by's splits "back by one"将 partition-by 的拆分“向后移动”
【发布时间】:2016-12-16 20:01:35
【问题描述】:

我在 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 %)) 发生变化时,就会发生分区(这是文档所说的)。

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

【问题讨论】:

    标签: clojure functional-programming enumeration clojurescript seq


    【解决方案1】:

    这是一种方法:

    (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]]]
    

    【讨论】:

    • 这适用于该示例,但据我了解,它会为它看到的每个 :h3 生成一个 [:ul [:li
    • 这不是目标吗?否则你会怎么做?
    • 好吧,直率的做法是每次读取的元素是 :h3 时折叠并检查累积结果,但我希望有更好的东西。
    • 添加了将所有:h3 放入同一个:ul 的更新。问题一定要准确! ;)
    • 对不起!我整天都在标记领域,没有考虑上下文。
    【解决方案2】:

    这是一个可以完成这项工作的答案,但非常不优雅,因为它本质上会在必要时改变 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"]]]]
    

    【讨论】:

      猜你喜欢
      • 2022-01-09
      • 2019-09-16
      • 1970-01-01
      • 2013-10-11
      • 1970-01-01
      • 2019-02-18
      • 1970-01-01
      • 1970-01-01
      • 2021-12-01
      相关资源
      最近更新 更多