Reputation:
Given this map:
{:a nil
:b {:c nil
:d 2
:e {:f nil
:g 4}}}
I need a function to remove all nil values, so that the returned map is
{:b {:e {:g 4}
:d 2}}
Or, when given:
{:a nil
:b {:c nil
:d nil
:e {:f nil
:g nil}}}
The result is:
nil
This question has an answer containing a function that supposedly works for nested maps, but that function fails when given a map that is nested more than one level deep.
Upvotes: 4
Views: 1974
Reputation: 10075
Using specter you can do it like this:
(declarepath DEEP-MAP-VALS)
(providepath DEEP-MAP-VALS (if-path map? [(compact MAP-VALS) DEEP-MAP-VALS] STAY))
(setval [DEEP-MAP-VALS nil?] NONE
{:a nil
:b {:c nil
:d 2
:e {:f nil
:g 4}}})
Please note it will return :com.rpl.specter.impl/NONE
instead of nil
if nothing is left.
This is partial reuse of this answer
Upvotes: 2
Reputation: 1261
modification of answer from here https://stackoverflow.com/a/22186735/1393248
(defn remove-nils
"remove pairs of key-value that has nil value from a (possibly nested) map. also transform map to nil if all of its value are nil"
[nm]
(clojure.walk/postwalk
(fn [el]
(if (map? el)
(not-empty (into {} (remove (comp nil? second)) el))
el))
nm))
Upvotes: 8
Reputation: 2491
(defn clean [m]
(if (map? m)
(let [clean-val (fn [[k v]]
(let [v' (clean v)]
(when-not (nil? v')
[k v'])))
m' (->> (map clean-val m)
(remove nil?)
(into {}))]
(when-not (empty? m') m'))
m))
Upvotes: 1