Skip to content

Commit e7e81e1

Browse files
committed
add merge-deep, merge-deep-with and direct tests
1 parent a5e94c9 commit e7e81e1

2 files changed

Lines changed: 88 additions & 0 deletions

File tree

‎src/main/cljs/cljs/core.cljs‎

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9326,6 +9326,34 @@ reduces them without incurring seq initialization"
93269326
(next keys)))
93279327
(-with-meta (persistent! ret) (meta map)))))
93289328

9329+
(defn merge-deep
9330+
"Returns a map that consists of the rest of the maps conj-ed onto
9331+
the first. For each pairwise merge, when a key occurs in both maps,
9332+
if both values are maps, then recursively merge-deep, else use the
9333+
latter (left-to-right) value."
9334+
{:added "1.13"}
9335+
[& maps]
9336+
(apply merge-with
9337+
(fn [x y]
9338+
(if (and (map? x) (map? y))
9339+
(merge-deep x y)
9340+
y))
9341+
maps))
9342+
9343+
(defn merge-deep-with
9344+
"Returns a map that consists of the rest of the maps conj-ed onto
9345+
the first. For each pairwise merge, when a key occurs in both maps,
9346+
if both values are maps, then recursively merge-deep-with, else use
9347+
the result of (f val-in-prior val-in-latter)."
9348+
{:added "1.13"}
9349+
[f & maps]
9350+
(apply merge-with
9351+
(fn [x y]
9352+
(if (and (map? x) (map? y))
9353+
(merge-deep-with f x y)
9354+
(f x y)))
9355+
maps))
9356+
93299357
;;; PersistentHashSet
93309358

93319359
(declare TransientHashSet)

‎src/test/cljs/cljs/core_test.cljs‎

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2136,3 +2136,63 @@
21362136
:select _})]
21372137
(is (= {::x 10000 :nested {:aa 1 'saa 10}}
21382138
(exnest_ sample-map)))))))
2139+
2140+
(deftest test-merge-deep
2141+
;; 0 arity
2142+
(is (nil? (merge-deep)))
2143+
2144+
;; 1 arity
2145+
(is (nil? (merge-deep nil)))
2146+
(is (= {:a 1} (merge-deep {:a 1})))
2147+
2148+
;; 2 arity
2149+
(are [expected x y] (= expected (merge-deep x y))
2150+
nil nil nil
2151+
{} {} nil
2152+
{} nil {}
2153+
;; latter value wins at same key if not both maps
2154+
{:a 1} {:a 1} nil ;; non-map + missing
2155+
{:a 1} nil {:a 1} ;; missing + non-map
2156+
{:a nil} {:a 1} {:a nil} ;; non-map + nil
2157+
{:a 1} {:a nil} {:a 1} ;; nil + non-map
2158+
{:a 2} {:a 1} {:a 2} ;; non-map + non-map
2159+
{:a {:x 1}} nil {:a {:x 1}} ;; missing + map
2160+
{:a {:x 1}} {:a {:x 1}} nil ;; map + missing
2161+
{:a {:x 1}} {:a nil} {:a {:x 1}} ;; nil + map
2162+
{:a nil} {:a {:x 1}} {:a nil} ;; map + nil
2163+
{:a {:x 2}} {:a {:x 1}} {:a {:x 2}} ;; map + map
2164+
;; more nesting
2165+
{:a {:b {:c 2}}} {:a {:b {:c 1}}} {:a {:b {:c 2}}}
2166+
;; vector is associative, but not a map - first arg dominates
2167+
[:c :d] [:a :b] {0 :c 1 :d}
2168+
{0 :a 1 :b} {0 :c 1 :d} [:a :b])
2169+
2170+
;; 3 arity
2171+
(are [expected x y z] (= expected (merge-deep x y z))
2172+
nil nil nil nil
2173+
{} {} nil nil
2174+
;; missing
2175+
{:a 3} nil {:a 2} {:a 3}
2176+
{:a 3} {:a 1} nil {:a 3}
2177+
{:a 2} {:a 1} {:a 2} nil
2178+
;; nil
2179+
{:a 3} {:a nil} {:a 2} {:a 3}
2180+
{:a nil} {:a 1} {:a 2} {:a nil}
2181+
;; non-maps
2182+
{:a 3} {:a 1} {:a 2} {:a 3}
2183+
;; mix - last wins
2184+
{:a nil} {:a 1} {:a {:x 1}} {:a nil}
2185+
;; maps
2186+
{:a {:x 3}} {:a {:x 1}} {:a {:x 2}} {:a {:x 3}}))
2187+
2188+
(deftest test-merge-deep-with
2189+
(are [expected x y] (= expected (merge-deep-with vector x y))
2190+
{:a nil} nil {:a nil}
2191+
{:a 1} nil {:a 1}
2192+
{:a [1 nil]} {:a 1} {:a nil}
2193+
{:a [1 2]} {:a 1} {:a 2})
2194+
(let [vectorizer (fn [x y] (if (vector? x) (conj x y) [x y]))]
2195+
(are [expected x y z] (= expected (merge-deep-with vectorizer x y z))
2196+
{:a [1 2 3]} {:a 1} {:a 2} {:a 3}
2197+
{:a [1 2]} {:a 1} {:a 2} nil)))
2198+

0 commit comments

Comments
 (0)