On Sun, Dec 5, 2010 at 10:03 PM, Ken Wesson <kwess...@gmail.com> wrote:
> On Sun, Dec 5, 2010 at 9:12 PM, Alex Baranosky
> <alexander.barano...@gmail.com> wrote:
>> Hi guys,
>> I would like a function to be able to take an arbitrarily nested collection
>> and return a sequence of all values of a given key, such as :name, that
>> appears anywhere in the nested collection.
>> Does anything like this already exist?
>
> It does now:
>
> (defn values-of [k coll]
>  (if-let [s (try (seq coll) (catch Exception _ nil))]
>    (let [not-found (Object.)
>          v (if (associative? coll) (get coll k not-found) not-found)
>          v (if-not (= v not-found) [v])
>          vs (map #(values-of k %) s)]
>      (apply concat v vs))))
>
> user=> (values-of :k [1 2 {:k 3 :l 4} 5 #{6} [[{:k 2}] {:k {:a 3 :k 7}}]])
> (3
>  2
>  {:a 3, :k 7}
>  7)
>
> It won't quite work perfectly for java.util collections, specifically
> because (associative? (java.util.HashMap.)) comes back false for some
> reason.

This should work even for Java collections including maps:

(defn values-of [k coll]
  (if (instance? java.util.Map$Entry coll)
    (recur k [(key coll) (val coll)])
    (if-let [s (try (seq coll) (catch Exception _ nil))]
      (let [not-found (Object.)
            v (if (or (associative? coll) (instance? java.util.Map coll))
                (get coll k not-found) not-found)
            v (if-not (= v not-found) [v])
            vs (map #(values-of k %) s)]
        (apply concat v vs)))))

user=> (values-of :k (doto (java.util.HashMap.) (.put :k "foo")))
("foo")
user=> (values-of :k (doto (java.util.HashMap.) (.put {:k 3} "foo")))
(3)

The new if at the start is because Clojure doesn't treat non-Clojure
Map$Entries as equivalent to [key val] so I turn all Map$Entries into
such vectors manually.

As you can see, it will delve into both the keys and the values of
even java.util Maps now.

-- 
You received this message because you are subscribed to the Google
Groups "Clojure" group.
To post to this group, send email to clojure@googlegroups.com
Note that posts from new members are moderated - please be patient with your 
first post.
To unsubscribe from this group, send email to
clojure+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en

Reply via email to