Skip to content

Instantly share code, notes, and snippets.

@eneroth
Last active August 2, 2018 14:06
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save eneroth/81fe5acf0aab82c355889f28887e08ca to your computer and use it in GitHub Desktop.
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
(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