Skip to content

Instantly share code, notes, and snippets.

@petrounias
Last active August 22, 2021 12:16
Show Gist options
  • Save petrounias/afa0ff32cc6b3adcf3a7b994119d8512 to your computer and use it in GitHub Desktop.
Save petrounias/afa0ff32cc6b3adcf3a7b994119d8512 to your computer and use it in GitHub Desktop.
Clojure safe merge performance
(require '[criterium.core :as crit])
; figuring out the most performant way to merge two maps with only non-nil values in the right hand map,
; without failing for `false` values:
;
; (safe-merge {:foo true :bar 4} {:foo false :bar nil})
; => {:foo false, :bar 4}
;
; ordered by decreasing execution time mean
(defn discard-nils-with-remove
[record]
(into {} (remove (comp nil? second) record)))
(def safe-merge-with-remove
(fn [left right]
(merge left (discard-nils-with-remove right))))
(crit/quick-bench (safe-merge-with-remove {:foo true :bar 4} {:foo false :bar nil}))
;Evaluation count : 837252 in 6 samples of 139542 calls.
;Execution time mean : 716,944000 ns
;Execution time std-deviation : 6,620577 ns
;Execution time lower quantile : 712,552730 ns ( 2,5%)
;Execution time upper quantile : 728,307484 ns (97,5%)
;Overhead used : 1,593551 ns
(defn discard-nils-with-dissoc
[record]
(apply dissoc
record
(for [[k v] record :when (nil? v)] k)))
(def safe-merge-with-dissoc
(fn [left right]
(merge left (discard-nils-with-dissoc right))))
(crit/quick-bench (safe-merge-with-dissoc {:foo true :bar 4} {:foo false :bar nil}))
;Evaluation count : 1277178 in 6 samples of 212863 calls.
;Execution time mean : 489,711185 ns
;Execution time std-deviation : 40,664672 ns
;Execution time lower quantile : 467,307104 ns ( 2,5%)
;Execution time upper quantile : 558,916085 ns (97,5%)
;Overhead used : 1,593551 ns
(defn discard-nils-with-merge
[record]
(apply merge (for [[k v] record :when (not (nil? v))] {k v})))
(def safe-merge-with-merge
(fn [left right]
(merge left (discard-nils-with-merge right))))
(crit/quick-bench (safe-merge-with-merge {:foo true :bar 4} {:foo false :bar nil}))
;Evaluation count : 1393698 in 6 samples of 232283 calls.
;Execution time mean : 430,248286 ns
;Execution time std-deviation : 2,328043 ns
;Execution time lower quantile : 428,329004 ns ( 2,5%)
;Execution time upper quantile : 433,656449 ns (97,5%)
;Overhead used : 1,593551 ns
(require '[clojure.core.match :refer [match]])
(defn discard-nils-with-match [a b]
(match [a b]
[_ nil] a
:else b))
(def safe-merge-with-match
(partial merge-with discard-nils-with-match))
(crit/quick-bench (safe-merge-with-match {:foo true :bar 4} {:foo false :bar nil}))
;Evaluation count : 1775166 in 6 samples of 295861 calls.
;Execution time mean : 339,427178 ns
;Execution time std-deviation : 3,205639 ns
;Execution time lower quantile : 336,055550 ns ( 2,5%)
;Execution time upper quantile : 343,214908 ns (97,5%)
;Overhead used : 1,593551 ns
(defn discard-nils
[a b]
(if (nil? b) a b))
(def safe-merge
(partial merge-with discard-nils))
(crit/quick-bench (safe-merge {:foo true :bar 4} {:foo false :bar nil}))
;Evaluation count : 1348296 in 6 samples of 224716 calls.
;Execution time mean : 332,508236 ns
;Execution time std-deviation : 4,311911 ns
;Execution time lower quantile : 327,409726 ns ( 2,5%)
;Execution time upper quantile : 337,967775 ns (97,5%)
;Overhead used : 1,593551 ns
(defn assoc-some
([m k v]
(if (nil? v) m (assoc m k v)))
([m k v & kvs]
(reduce
(fn [m [k v]] (assoc-some m k v))
(assoc-some m k v)
(partition 2 kvs))))
(def safe-merge-with-assoc
(fn [left right]
(reduce (fn [l [k v]] (assoc-some l k v)) left right)))
(crit/quick-bench (safe-merge-with-assoc {:foo true :bar 4} {:foo false :bar nil}))
;Evaluation count : 2765952 in 6 samples of 460992 calls.
;Execution time mean : 156,734179 ns
;Execution time std-deviation : 3,658107 ns
;Execution time lower quantile : 153,871837 ns ( 2,5%)
;Execution time upper quantile : 162,657836 ns (97,5%)
;Overhead used : 1,593551 ns
(def safe-merge-with-assoc-direct
(fn [left right]
(reduce (fn [left [k v]] (if (nil? v) left (assoc left k v))) left right)))
(crit/quick-bench (safe-merge-with-assoc-direct {:foo true :bar 4} {:foo false :bar nil}))
;Evaluation count : 2709996 in 6 samples of 451666 calls.
;Execution time mean : 138,728946 ns
;Execution time std-deviation : 3,859391 ns
;Execution time lower quantile : 136,412854 ns ( 2,5%)
;Execution time upper quantile : 145,326409 ns (97,5%)
;Overhead used : 1,593551 ns
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment