Обрезать ненужные записи из глубоко вложенной структуры данных, используя спектр - PullRequest
2 голосов
/ 11 июля 2019

Я хочу использовать Clojure Spectre для упрощения глубоко вложенной структуры данных. Я хочу удалить:

  • любые записи со значениями nil
  • любые записи с пустыми строковыми значениями
  • любые записи с пустыми значениями карты
  • любые записи с пустыми последовательными значениями
  • любые записи с картами / последовательными значениями, которые являются пустыми после удаления вышеуказанных случаев.

Примерно так:

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

2 голосов
/ 11 июля 2019

Сравнение производительности разных версий с реализацией Spectre:

@ 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 голос
/ 12 июля 2019

Благодаря nathanmarz в канале Clojurians:

(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))
...