Last active
August 2, 2018 14:06
-
-
Save eneroth/81fe5acf0aab82c355889f28887e08ca to your computer and use it in GitHub Desktop.
Recursively strips values that are nil from a data structure. Will strip entire branches if they recursively evaluate to nil
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
(defn safe-seq | |
[thing] | |
(if (seqable? thing) | |
(seq thing) | |
true)) | |
(defprotocol StripNil | |
(strip-nil [data] | |
"Recursively strips values that are nil from a datastructure. | |
Will strip entire branches if they recursively evaluate to nil")) | |
(extend-type java.util.Map | |
StripNil | |
(strip-nil | |
[m] | |
(let [m-as-vec (vec m)] | |
(loop [entry (first m-as-vec) | |
remainder (rest m-as-vec) | |
collector {}] | |
(if-not entry | |
collector | |
(recur | |
(first remainder) | |
(rest remainder) | |
(let [[k v] entry | |
v (strip-nil v)] | |
(if (safe-seq v) | |
(assoc collector k v) | |
collector)))))))) | |
(extend-type clojure.lang.PersistentList | |
StripNil | |
(strip-nil | |
[coll] | |
(let [xf (comp (map strip-nil) | |
(filter safe-seq))] | |
(sequence xf coll)))) | |
(extend-type clojure.lang.PersistentVector | |
StripNil | |
(strip-nil | |
[coll] | |
(let [xf (comp (map strip-nil) | |
(filter safe-seq))] | |
(vec (sequence xf coll))))) | |
(extend-type nil | |
StripNil | |
(strip-nil | |
[thing] | |
thing)) | |
(extend-type java.lang.Object | |
StripNil | |
(strip-nil | |
[thing] | |
thing)) | |
;; Test it | |
;; ################################## | |
(def t [{:moose-says "blaaargh" | |
:giant {:weapon nil} | |
:tower nil | |
:elf {:can-see "bridge"} | |
:elf/thinking-of [{:item/pastry "cake"} | |
{:item/weapon nil} | |
{:location/land "home"} | |
{:location/water nil}] | |
:elf/hat [{:actually nil}]}]) | |
(def f [{:id #uuid "2115b649-006f-4159-b820-62450f90b51d"}]) | |
(strip-nil t) | |
;; => [{:moose-says "blaaargh" | |
;; :elf {:can-see "bridge"} | |
;; :elf/thinking-of [{:item/pastry "cake"} | |
;; {:location/land "home"} | |
;; Before safe-empty? | |
(strip-nil f) | |
;; => IllegalArgumentException Don't know how to create ISeq from: java.util.UUID | |
;; clojure.lang.RT.seqFrom (RT.java:550) | |
;; After safe-empty? | |
(strip-nil f) | |
;; => [{:id #uuid "2115b649-006f-4159-b820-62450f90b51d"}] | |
(safe-empty? (java.util.UUID/randomUUID)) | |
;; => false |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment