Interesting problem. This is my (first iteration) of a solution:

--8<---------------cut here---------------start------------->8---
(defn select-in [m keyseq]
  (loop [acc {} [k & ks] (seq keyseq)]
    (if k
      (recur
       (if (sequential? k)
         (let [[k ks] k]
           (assoc acc k
                  (select-in (get m k) ks)))
         (assoc acc k (get m k)))
       ks)
      acc)))
--8<---------------cut here---------------end--------------->8---

The `keyseq' parameter uses seqs instead of the maps in your example,
but I think the usage is fairly convenient:

--8<---------------cut here---------------start------------->8---
(select-in my-map [:name
                   :email
                   [:address [:city
                              :state]]
                   [:spouse [:name
                             [:address [:city
                                        :state]]]]])
--8<---------------cut here---------------end--------------->8---


One thing to notice is that this function doesn't work as intended on
maps with seqs as keys. It's also not tail-recursive but maps nested so
deep that this becomes a problem are a problem by itself.


Baishampayan Ghose <b.gh...@gmail.com> writes:

> Hi,
>
> I have a problem wherein I need to select subsets of a given map;
> think about select-keys, but with arbitrary nesting.
>
> For example, consider this map -
>
> (def my-map {:name "John Doe"
>                :email "j...@doe.com"
>                :address {:house "42"
>                          :street "Moon St."
>                          :city "San Francisco"
>                          :state "CA"
>                          :zip 76509
>                          :mobile "+188888888"}
>                :ssn "123456"
>                :spouse {:name "Jane Doe"
>                         :ssn "654321"
>                         :relation :wife
>                         :address {:house "42"
>                                   :street "Moon St."
>                                   :city "Atlanta"
>                                   :state "GA"
>                                   :zip 76509
>                                   :mobile "+188888888"}}})
>
> From the above map, I want to extract this sub-map -
>
> {:spouse {:name "Jane Doe", :address {:state "GA", :city "Atlanta"}},
>  :name "John Doe",
>  :email "j...@doe.com",
>  :address {:state "CA", :city "San Francisco"}}
>
> What would be a good way to express this sub-map so that I can pass it
> on to a function?
>
> I am thinking about something like this -
>
> [:name :email {:address [:city :state]} {:spouse [:name {:address
> [:city :state]}]}]
>
> Example implementations are also welcome.
>
> Regards,
> BG
>
> --
> Baishampayan Ghose
> b.ghose at gmail.com

--
Moritz Ulrich

-- 
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