Last active
September 4, 2023 22:16
-
-
Save paultopia/78ba6791d7eba48293da45d9d5d58c57 to your computer and use it in GitHub Desktop.
merge for clojure that doesn't overwrite existing values with nil values
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(require '[clojure.core.match :refer [match]]) | |
(defn discard-nils [a b] | |
(match [a b] | |
[_ nil] a | |
:else b)) | |
(def safe-merge (partial merge-with discard-nils)) | |
;; examples | |
(safe-merge {:a 1 :b 1} {:a 5 :b nil} {:a nil :b 3}) | |
;; => {:a 5, :b 3} | |
(merge {:a 1 :b 1} {:a 5 :b nil} {:a nil :b 3}) | |
;; => {:a nil, :b 3} | |
(safe-merge {:a 1 :b nil} {:a nil :b 4 :c 5 :d nil}) | |
;; => {:a 1, :b 4, :c 5, :d nil} | |
(merge {:a 1 :b nil} {:a nil :b 4 :c 5 :d nil}) | |
;; => {:a nil, :b 4, :c 5, :d nil} |
Using core.match
looks a bit overengineered here. if/else logic would be enough:
(defn discard-nils
[a b]
(if (nil? b) a b))
(def safe-merge (partial merge-with #(or %2 %1)))
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Use case for this: data collection and parsing projects that rely on maps stored in mutable state.
I'm working on a complex human/computer web data collection project that takes the html from a webpage via a chrome extension, parses it out, with a combination of enlive and regex, into a map, and sends it to a server to be stored in an atom until the human driving the browser answers some questions about it, at which time it's entered into a database.
But the webpage sometimes gets updated by ajax calls, and my chrome extension will scrape that data too and send it to the server to be merged with the existing data.
What happens if a subsequent update of the webpage destroys some data that my parsers found on the initial webpage? If I just merged the maps via the standard
merge
function in clojure.core, parsing the second version of the page would returnnil
for the destroyed data, and then merge would lose the first version of the page. That's no good.safe-merge
prefers later data to former, but prefers non-nil data to nil data, and the preference for non-nil trumps the preference for later data. Problem solved.