Reputation: 1267
I'm trying to deep-merge multiple maps in Clojure. I found many solutions online, most of which look something like:
(defn deep-merge
[& xs]
(if (every? map? xs)
(apply merge-with deep-merge xs)
(last xs)))
The problem with this solution is that if one of the maps is nil, it will delete all the previous maps (so if the last map is nil, the whole function will return nil). This is not the case in the regular merge function, which ignores nil values. Is there any other easy implementation of deep-merge that ignores nil values?
Upvotes: 5
Views: 1342
Reputation: 1267
I found this at: https://github.com/circleci/frontend/blob/04701bd314731b6e2a75c40085d13471b696c939/src-cljs/frontend/utils.cljs. It does exactly what it should.
(defn deep-merge* [& maps]
(let [f (fn [old new]
(if (and (map? old) (map? new))
(merge-with deep-merge* old new)
new))]
(if (every? map? maps)
(apply merge-with f maps)
(last maps))))
(defn deep-merge [& maps]
(let [maps (filter identity maps)]
(assert (every? map? maps))
(apply merge-with deep-merge* maps)))
Thank you CircleCi people!
Upvotes: 7
Reputation: 13473
Remove the nil
s at once?
(defn deep-merge [& xs]
(let [xs (remove nil? xs)]
(if (every? map? xs)
(apply merge-with deep-merge xs)
(last xs))))
Upvotes: 2