1

So, as a result of a database call, I get a vector of maps, which let's say look like this:

[{:make "vw",  :model "vanagon", :color "blue",   :year 1983}
 {:make "vw",  :model "vanagon", :color "red",    :year 1987}
 {:make "vw",  :model "eurovan", :color "blue",   :year 1995}
 {:make "vw",  :model "eurovan", :color "green",  :year 1997}
 {:make "geo", :model "metro",   :color "blue",   :year 1985}
 {:make "geo", :model "metro",   :color "yellow", :year 1994}]

How can I get that into a nested map using two of the fields, e.g. like this:

{"vw"  {"vanagon" [{:color "blue", :year 1983}, {:color "red", :year 1987}]
        "eurovan" [{:color "blue", :year 1995}, {:color "green", :year 1997}]}
 "geo" {"metro" [{:color "blue", :year 1985}, {:color "yellow", :year 1994}]}}

I have been messing around with group-by and other coll functions for a couple hours, and I can't wrap my head around it and figure out a reasonable way to do this.

Thanks!

1 Answer 1

5
(reduce (fn [aggr {:keys [make model] :as row}]
          (update-in aggr
                     [make model]
                     (fnil conj [])
                     (dissoc row :make :model)))
        {} data)

The anonymous function does a destructuring bind. update-in rewrites bound structure. The basic idea is to use conj to add in the other elements of the row. fnil is there to specify that we want vectors (when nil is found use the empty vector as the 1st argument to conj). Results are combined in a map by reduce.

Sign up to request clarification or add additional context in comments.

3 Comments

Awesome! Still need to completely grok what's going on there, but this does the trick. Thank you!
As a follow-up, though, what if I don't necessarily know all of the items in the maps that aren't use to construct the hierarchy? E.g. what if the original maps may have additional entries, and I want them in the leaf maps at the end, without knowing ahead of time what they are?
Edited my answer to preserve any entry not used for the path.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.