Given:
{:o {:i1 1 :i2 {:ii1 4}}}
I'd like to iterate over the keys of the map in "absolute" form from the root as a vector. So I'd like:
{ [:o :i1] 1 [:o :i2 :ii1] 4 }
As the result. Basically only get the leaf nodes.
Given:
{:o {:i1 1 :i2 {:ii1 4}}}
I'd like to iterate over the keys of the map in "absolute" form from the root as a vector. So I'd like:
{ [:o :i1] 1 [:o :i2 :ii1] 4 }
As the result. Basically only get the leaf nodes.
A version that I think is rather nicer, using for
instead of mapcat
:
(defn flatten-keys [m] (if (not (map? m)) {[] m} (into {} (for [[k v] m [ks v'] (flatten-keys v)] [(cons k ks) v']))))
The function is naturally recursive, and the most convenient base case for a non-map is "this one value, with no keyseq leading to it". For a map, you can just call flatten-keys
on each value in the map, and prepend its key to each keyseq of the resulting map.
Looks like this is basically a flatten of the nested keys. This also seems to be a 4clojure problem.
A flatten-map search on github yield many results.
One example implementation:
(defn flatten-map "Flattens the keys of a nested into a map of depth one but with the keys turned into vectors (the paths into the original nested map)." [s] (let [combine-map (fn [k s] (for [[x y] s] {[k x] y}))] (loop [result {}, coll s] (if (empty? coll) result (let [[i j] (first coll)] (recur (into result (combine-map i j)) (rest coll)))))))
Example
(flatten-map {:OUT {:x 5 :x/A 21 :x/B 33 :y/A 24}}) => {[:OUT :x] 5, [:OUT :x/A] 21, [:OUT :x/B] 33, [:OUT :y/A] 24}
An even more general version from Christoph Grand:
(defn flatten-map "Take a nested map (or a nested collection of key-value pairs) and returns a sequence of key-value pairs where keys are replaced by the result of calling (reduce f pk path) where path is the path to this key through the nested maps." ([f kvs] (flatten-map f nil kvs)) ([f pk kvs] (mapcat (fn [[k v]] (if (map? v) (flatten-map f (f pk k) v) [[(f pk k) v]])) kvs)))
Example:
(flatten-map conj [] {:OUT {:x 5 :x/A 21 :x/B 33 :y/A 24}}) => ([[:OUT :x] 5] [[:OUT :x/A] 21] [[:OUT :x/B] 33] [[:OUT :y/A] 24])