Search code examples
clojure

Clojure convert vector of maps into map of vector values


There are a few SO posts related to this topic, however I could not find anything that works for what I am looking to accomplish.

I have a vector of maps. I am going to use the example from another related SO post:

(def data
   [{:id 1 :first-name "John1" :last-name "Dow1" :age "14"}
    {:id 2 :first-name "John2" :last-name "Dow2" :age "54"}
    {:id 3 :first-name "John3" :last-name "Dow3" :age "34"}
    {:id 4 :first-name "John4" :last-name "Dow4" :age "12"}
    {:id 5 :first-name "John5" :last-name "Dow5" :age "24"}]))

I would like to convert this into a map with the values of each entry be a vector of the associated values (maintaining the order of data).

Here is what I would like to have as the output:

{:id [1 2 3 4 5]
 :first-name ["John1" "John2" "John3" "John4" "John5"]
 :last-name ["Dow1" "Dow2" "Dow3" "Dow4" "Dow5"]
 :age ["14" "54" "34" "12" "24"]}

Is there an elegant and efficient way to do this in Clojure?


Solution

  • Can be made more efficient, but this is a nice start:

    (def ks (keys (first data)))
    (zipmap ks (apply map vector (map (apply juxt ks) data))) ;;=> 
    
    {:id [1 2 3 4 5]
     :first-name ["John1" "John2" "John3" "John4" "John5"]
     :last-name ["Dow1" "Dow2" "Dow3" "Dow4" "Dow5"]
     :age ["14" "54" "34" "12" "24"]}
    

    Another one that comes close:

    (group-by key (into [] cat data))
    
    ;;=> 
    {:id [[:id 1] [:id 2] [:id 3] [:id 4] [:id 5]],
     :first-name [[:first-name "John1"] [:first-name "John2"] [:first-name "John3"] [:first-name "John4"] [:first-name "John5"]],
     :last-name [[:last-name "Dow1"] [:last-name "Dow2"] [:last-name "Dow3"] [:last-name "Dow4"] [:last-name "Dow5"]],
     :age [[:age "14"] [:age "54"] [:age "34"] [:age "12"] [:age "24"]]}