Clojure: Get All Nested Map Values (N levels deep)
I recently needed to pull all the values from a nested map. The map I was working with was designed to give easy access to data like so (formatted):user=>
(def my-data {"Jay"
{"clojure"
{:name "Jay", :language "clojure", :enjoys true},
"ruby"
{:name "Jay", :language "ruby", :enjoys true}}
"Jon"
{"java"
{:name "Jon", :language "java", :enjoys true}}} )
#'user/my-data
user=> (get-in my-data ["Jon" "java"])
{:name "Jon", :language "java", :enjoys true}
user=> (get-in my-data ["Jay" "ruby"])
{:name "Jay", :language "ruby", :enjoys true} This worked for all of the ways the data was accessed, until someone asked for a list of all people and all languages.
I needed a function that grabbed all the values nested to a point in the map (grabbing only the values instead of the deepest map wouldn't have provided valuable information. I created the following function that should grab all the values up to the nesting level specified.(defn nth-vals* [a i m]
(if (and (map? m) (> i 0))
(reduce into a (map (fn [v] (nth-vals* a (dec i) v)) (vals m)))
(conj a m)))
(defn nth-vals [i m]
(if (nil? m)
{}
(nth-vals* [] i m)))The nth-vals function can be used as the following example shows. (assuming the same map for my-data)user=> (nth-vals 2 my-data)
[{:name "Jay", :language "clojure", :enjoys true} {:name "Jay", :language "ruby", :enjoys true} {:name "Jon", :language "java", :enjoys true}]For reference, here's what's returned if we reduce the map all the way to it's values.user=> (nth-vals 3 my-data)
["Jay" "clojure" true "Jay" "ruby" true "Jon" "java" true]That list of values may be helpful for someone else, but it wouldn't have solved our current problem.
And, if you're interested, here's what's returned if you ask for 1 level deep of values. (formatted, again)user=> (nth-vals 1 my-data)
[{"clojure" {:name "Jay", :language "clojure", :enjoys true},
"ruby" {:name "Jay", :language "ruby", :enjoys true}}
{"java" {:name "Jon", :language "java", :enjoys true}}]I wouldn't at all be surprised if something like this already exists in Clojure core, but I haven't found it yet. Hopefully
© Jay Fields - www.jayfields.com
(def my-data {"Jay"
{"clojure"
{:name "Jay", :language "clojure", :enjoys true},
"ruby"
{:name "Jay", :language "ruby", :enjoys true}}
"Jon"
{"java"
{:name "Jon", :language "java", :enjoys true}}} )
#'user/my-data
user=> (get-in my-data ["Jon" "java"])
{:name "Jon", :language "java", :enjoys true}
user=> (get-in my-data ["Jay" "ruby"])
{:name "Jay", :language "ruby", :enjoys true} This worked for all of the ways the data was accessed, until someone asked for a list of all people and all languages.
I needed a function that grabbed all the values nested to a point in the map (grabbing only the values instead of the deepest map wouldn't have provided valuable information. I created the following function that should grab all the values up to the nesting level specified.(defn nth-vals* [a i m]
(if (and (map? m) (> i 0))
(reduce into a (map (fn [v] (nth-vals* a (dec i) v)) (vals m)))
(conj a m)))
(defn nth-vals [i m]
(if (nil? m)
{}
(nth-vals* [] i m)))The nth-vals function can be used as the following example shows. (assuming the same map for my-data)user=> (nth-vals 2 my-data)
[{:name "Jay", :language "clojure", :enjoys true} {:name "Jay", :language "ruby", :enjoys true} {:name "Jon", :language "java", :enjoys true}]For reference, here's what's returned if we reduce the map all the way to it's values.user=> (nth-vals 3 my-data)
["Jay" "clojure" true "Jay" "ruby" true "Jon" "java" true]That list of values may be helpful for someone else, but it wouldn't have solved our current problem.
And, if you're interested, here's what's returned if you ask for 1 level deep of values. (formatted, again)user=> (nth-vals 1 my-data)
[{"clojure" {:name "Jay", :language "clojure", :enjoys true},
"ruby" {:name "Jay", :language "ruby", :enjoys true}}
{"java" {:name "Jon", :language "java", :enjoys true}}]I wouldn't at all be surprised if something like this already exists in Clojure core, but I haven't found it yet. Hopefully
© Jay Fields - www.jayfields.com
Published on May 04, 2011 17:26
No comments have been added yet.


