clojureclojurescriptedn

ClojureScript search in nested map and vector


I have an edn in which I have nested maps. I found one very good example for this Clojure: a function that search for a val in a nested hashmap and returns the sequence of keys in which the val is contained

(def coll
  {:a "aa"
   :b {:d "dd"
       :e {:f {:h "hh"
               :i "ii"}
           :g "hh"}}
   :c "cc"})

With this answer

(defn find-in [coll x]
    (some
(fn [[k v]]
  (cond (= v x) [k]
        (map? v) (if-let [r (find-in v x)]
                   (into [k] r))))
coll))

My problem is that because of some I can't get a path for every result, only for the first logical truth. I tried map an keep but they break the recursion. How could I make this code to give back path to all of its results, not only the first one? Any help is appreciated.


Solution

  • You can use a helper function to turn a nested map into a flat map with fully qualified keys. Then find-in can just filter on the value and returns the matched keys.

    (defn flatten-map [path m]
      (if (map? m)
        (mapcat (fn [[k v]] (flatten-map (conj path k) v)) m)
        [[path m]]))
    
    (defn find-in [coll x]
      (->> (flatten-map [] coll)
           (filter (fn [[_ v]] (= v x)))
           (map first)))
    

    With your sample:

    (find-in coll "hh")
    =>
    ([:b :e :f :h] [:b :e :g])