使用Spectre从深度嵌套的数据结构中修剪不必要的条目

时间:2019-07-11 14:08:07

标签: clojure specter

我正在寻找使用Clojure Spectre来简化深度嵌套的数据结构。我要删除:

  • 任何值为零的条目
  • 任何具有空字符串值的条目
  • 任何具有空映射值的条目
  • 任何具有空序列值的条目
  • 在删除上述情况后,任何具有映射/顺序值的条目都是空的。

类似这样的东西:

(do-something
    {:a {:aa 1}                                               
       :b {:ba -1                                               
           :bb 2                                                
           :bc nil
           :bd ""
           :be []
           :bf {}
           :bg {:ga nil}
           :bh [nil]
           :bi [{}]
           :bj [{:ja nil}]}
       :c nil
       :d ""
       :e []
       :f {}
       :g {:ga nil}
       :h [nil]
       :i [{}]
       :j [{:ja nil}]})
    =>
    {:a {:aa 1} 
         :b {:ba -1 
             :bb 2}}

我在香草Clojure中有一些东西

(defn prunable?
  [v]
  (if (sequential? v)
    (keep identity v)
    (or (nil? v) (#{"" [] {}} v))))

(defn- remove-nil-values
  [ticket]
  (clojure.walk/postwalk
    (fn [el]
      (if (map? el)
        (let [m (into {} (remove (comp prunable? second) el))]
          (when (seq m)
            m))
        el))
    ticket))

我认为我需要某种recursive-path,但是我不能很快到达任何地方。非常感谢。

2 个答案:

答案 0 :(得分:1)

比较不同版本的性能与幽灵实现:

@ bm1729普通香草版本:

Evaluation count : 1060560 in 60 samples of 17676 calls.
             Execution time mean : 57.083226 µs
    Execution time std-deviation : 543.184398 ns
   Execution time lower quantile : 56.559237 µs ( 2.5%)
   Execution time upper quantile : 58.519433 µs (97.5%)
                   Overhead used : 7.023993 ns

Found 5 outliers in 60 samples (8.3333 %)
    low-severe   3 (5.0000 %)
    low-mild     2 (3.3333 %)
 Variance from outliers : 1.6389 % Variance is slightly inflated by outliers

以下版本:

Evaluation count : 3621960 in 60 samples of 60366 calls.
             Execution time mean : 16.606135 µs
    Execution time std-deviation : 141.114975 ns
   Execution time lower quantile : 16.481250 µs ( 2.5%)
   Execution time upper quantile : 16.922734 µs (97.5%)
                   Overhead used : 7.023993 ns

Found 9 outliers in 60 samples (15.0000 %)
    low-severe   6 (10.0000 %)
    low-mild     3 (5.0000 %)
 Variance from outliers : 1.6389 % Variance is slightly inflated by outliers
(defn prune [x]
  (cond
    (map? x) (not-empty
              (reduce-kv
               (fn [s k v]
                 (let [v' (prune v)]
                   (cond-> s
                     v' (assoc k v'))))
               (empty x)
               x))

    (seqable? x) (not-empty
                  (into
                   (empty x)
                   (->> x (map prune) (filter identity))))

    :else x))

测试用例:

(prune {:a {:aa 1}
        :b  {:ba -1
             :bb 2
             :bc nil
             :bd ""
             :be []
             :bf {}
             :bg {:ga nil}
             :bh [nil]
             :bi [{}]
             :bj [{:ja nil}]}
        :c  nil
        :d  ""
        :e  []
        :f  {}
        :g  {:ga nil}
        :h  [nil]
        :i  [{}]
        :j  [{:ja nil}]})
;; => {:b {:bb 2, :ba -1}, :a {:aa 1}}

更新-@ bm1729幽灵版本

Evaluation count : 3314820 in 60 samples of 55247 calls.
             Execution time mean : 18.421613 µs
    Execution time std-deviation : 591.106243 ns
   Execution time lower quantile : 18.148204 µs ( 2.5%)
   Execution time upper quantile : 20.674292 µs (97.5%)
                   Overhead used : 7.065044 ns

Found 8 outliers in 60 samples (13.3333 %)
    low-severe   2 (3.3333 %)
    low-mild     6 (10.0000 %)
 Variance from outliers : 18.9883 % Variance is moderately inflated by outliers

答案 1 :(得分:1)

感谢Clojurians闲暇频道上的nathanmarz

(def COMPACTED-VALS-PATH
  (recursive-path [] p
                  (continue-then-stay
                    (cond-path
                      map? [(compact MAP-VALS) p]
                      vector? [(compact ALL) p]))))

(defn- compact-data
  [m]
  (setval [MAP-VALS COMPACTED-VALS-PATH #(or (nil? %) (= "" %))] NONE m))