Search code examples
dictionaryfilterclojure

Clojure - filter nested map on innermost level


what would be the best way of filtering the following nested map, keeping the nested map structure. In my example Alice and Bob can be duplicated, e.g. the same employee can be working in several different plants at a time.

(def universe
  {:customer1
    {:plant1
      { "Alice" {:age 35 :sex "F"}
        "Bob" {:age 25 :sex "M"}}
     :plant2 {}} 
   :customer2 {}
  })

I would like to for example filter by age >30 and return the same map structure. Ideally this would work for any nested map depth, filtering on the innermost level. Expected result:

(def universe
  {:customer1
    {:plant1
      { "Alice" {:age 35 :sex "F"}
        }
     :plant2 {}} 
   :customer2 {}
  })

I've looked at clojure filter nested map to return keys based on inner map values but it doesn't look to be solving my problem. Thank you,


Solution

  • It is very similar to one of previous questions:

    (use '[com.rpl.specter])
    (let [input          {:customer1
                                     {:plant1
                                              {"Alice" {:age 35 :sex "F"}
                                               "Bob"   {:age 25 :sex "M"}}
                                      :plant2 {}}
                          :customer2 {}}
          desired-output {:customer1
                                     {:plant1 {"Alice" {:age 35 :sex "F"}}
                                      :plant2 {}}
                          :customer2 {}}
          RECUR-MAP      (recursive-path [] p (cond-path map? (continue-then-stay [MAP-VALS p])))]
    
        (clojure.test/is (= (setval [RECUR-MAP (pred :age) #(> 30 (:age %))] NONE input)
                            desired-output)))