Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Dissoc multiple descendent keys of a map?

Tags:

clojure

How can I search and dissoc multiple descendent keys.

Example:

(def d {:foo 123
        :bar {
          :baz 456
          :bam {
            :whiz 789}}})

(dissoc-descendents d [:foo :bam])
;->> {:bar {:baz 456}}
like image 269
AnnanFay Avatar asked Mar 15 '12 14:03

AnnanFay


2 Answers

clojure.walk is useful in this kind of situations:

(use 'clojure.walk)
(postwalk #(if (map? %) (dissoc % :foo :bam) %) d)
like image 132
Jouni K. Seppänen Avatar answered Oct 14 '22 21:10

Jouni K. Seppänen


If you wanted to implement it directly then I'd suggest something like this:

(defn dissoc-descendents [coll descendents]
  (let [descendents (if (set? descendents) descendents (set descendents))]
    (if (associative? coll)
      (reduce
        (fn [m [k v]] (if (descendents k) 
                        (dissoc m k)
                        (let [new-val (dissoc-descendents v descendents)]
                          (if (identical? new-val v) m (assoc m k new-val)))))
        coll
        coll)
      coll)))

Key things to note about the implementation:

  • It makes sense to convert descendents into a set: this will allow quick membership tests if the set of keys to remove is large
  • There is some logic to ensure that if a value doesn't change, you don't need to alter that part of the map. This is quite a big performance win if large areas of the map are unchanged.
like image 1
mikera Avatar answered Oct 14 '22 21:10

mikera