Performance 以更快/更惯用的方式实现;何时映射;?

Performance 以更快/更惯用的方式实现;何时映射;?,performance,clojure,Performance,Clojure,我想实现一个函数,它映射一系列映射,并在谓词匹配时更新值 这是第一份工作草案: (defn update-if ([m k pred f] (let [init (get m k)] (if (and (not-nil? init) (pred init)) (update m k f) m))) ([m bindings] (reduce-kv (fn [agg k v] (let [[pred

我想实现一个函数,它映射一系列映射,并在谓词匹配时更新值

这是第一份工作草案:

(defn update-if
  ([m k pred f]
   (let [init (get m k)]
     (if (and (not-nil? init) (pred init))
           (update m k f)
           m)))
  ([m bindings]
   (reduce-kv
     (fn [agg k v]
       (let [[pred f] v]
         (update-if agg k pred f)))
    m bindings)))

(update-if {:a 1 :b 2} {:a [even? inc] :b [even? dec]}) ;; ==> {:a 1 :b 1}
(update-if {:a 1 :b 2} :b even? dec) ;; ==> {:a 1 :b 1}

(defn map-when
  "Walks a collection of associative collections
  and applies functions based on predicates
  Output :
  (map-when {:a [even? inc] :b [nan? zero]} '({:a 1 :b NaN} {:a 2 :b 7} {:a 4 :b NaN}))
  =
  ({:a 1 :b 0} {:a 3 :b 7} {:a 5 :b 0})"
  ([bindings data]
   (reduce
     (fn [acc row]
       (conj acc (update-if row bindings)))
    '() data))
  ([pred f data]
   (map
     (fn [x]
       (if (and (not-nil? x) (pred x))
             (f x)
             x))
    data)))
不是零吗?检查(这里)很重要,因为它只意味着数据丢失。 该函数在100万个随机
{:a:b}
贴图(包括随机生成)上执行此操作大约需要2秒

我觉得奇怪的是,在核心/核心相关库中没有这个函数。 是否有一些性能提示可以改进这一点?我尝试了transient,但它在空列表上不起作用。
'()

谢谢

你应该这么做。它可能有你想要的东西。例如:

(def data {:a [{:aa 1 :bb 2}
               {:cc 3}]
           :b [{:dd 4}]})

;; Manual Clojure
(defn map-vals [m afn]
  (->> m (map (fn [[k v]] [k (afn v)])) (into {})))

(map-vals data
  (fn [v]
    (mapv
      (fn [m]
        (map-vals
          m
          (fn [v] (if (even? v) (inc v) v))))
      v)))

;; Specter
(transform [MAP-VALS ALL MAP-VALS even?] inc data)
你应该。它可能有你想要的东西。例如:

(def data {:a [{:aa 1 :bb 2}
               {:cc 3}]
           :b [{:dd 4}]})

;; Manual Clojure
(defn map-vals [m afn]
  (->> m (map (fn [[k v]] [k (afn v)])) (into {})))

(map-vals data
  (fn [v]
    (mapv
      (fn [m]
        (map-vals
          m
          (fn [v] (if (even? v) (inc v) v))))
      v)))

;; Specter
(transform [MAP-VALS ALL MAP-VALS even?] inc data)

仅生成必要的lambda以最大限度地提高可重用性

(defn cond-update-fn [clauses]
  (fn [m] 
    (reduce (fn [m [k [pred f]]] 
               (cond-> m
                  (and (contains? m k)
                       (pred (get m k))) (update k f)))
      m 
      clauses)))
如果您的pred和fn在编译时已知,那么编写宏(留给读者作为练习)可以提供更高的性能,因为没有pred迭代开销


在任何上下文中重用:

(def input [{:a 42, :b 42} {:a 42,:b 43}])

(def cond-update 
  (cond-update-fn {:a [even? inc]
                   :b [odd? dec]}))

(map cond-update input)

;-> ({:a 43, :b 42} {:a 43, :b 42})

;; Transducer
(into [] (map cond-update) input)

;-> [{:a 43, :b 42} {:a 43, :b 42}]

;; Standalone

(cond-update {:a 32})
;-> {:a 33}

仅生成必要的lambda以最大限度地提高可重用性

(defn cond-update-fn [clauses]
  (fn [m] 
    (reduce (fn [m [k [pred f]]] 
               (cond-> m
                  (and (contains? m k)
                       (pred (get m k))) (update k f)))
      m 
      clauses)))
如果您的pred和fn在编译时已知,那么编写宏(留给读者作为练习)可以提供更高的性能,因为没有pred迭代开销


在任何上下文中重用:

(def input [{:a 42, :b 42} {:a 42,:b 43}])

(def cond-update 
  (cond-update-fn {:a [even? inc]
                   :b [odd? dec]}))

(map cond-update input)

;-> ({:a 43, :b 42} {:a 43, :b 42})

;; Transducer
(into [] (map cond-update) input)

;-> [{:a 43, :b 42} {:a 43, :b 42}]

;; Standalone

(cond-update {:a 32})
;-> {:a 33}