Clojure exercise to transpose three lists

Table of Contents

The need: take multiple vectors and view each vector as a column (not a row) of the data, so all the first items go together, all the second, etc. Here’s a rough version that felt too clunky (alert: it features a number) and fragile but happens to demonstrate the needs:

(let [[names jobs langs :as all] [["john" "jane" "michael"]
                                  ["chef" "driver" "vet"]
                                  ["English" "German" "French"]]]
        (map #(zipmap [:name :job :lang] %)
                (partition 3 
                           (interleave names jobs langs))))
;; ({:name "john", :job "chef", :lang "English"} 
;;  {:name "jane", :job "driver", :lang "German"} 
;;  {:name "michael", :job "vet", :lang "French"})

Solution

(let [[names jobs langs :as all] [["john" "jane" "michael"]
                                  ["chef" "driver" "vet"]
                                  ["English" "German" "French"]]]
        (apply map #(zipmap [:name :job :lang] %&) all))
;; => ({:name "john", :job "chef", :lang "English"} {:name "jane", :job "driver", :lang "German"} {:name "michael", :job "vet", :lang "French"})

This solution taught me two new things:

  1. that map and so zipmap can take any number of args, plucking the nth item of each collection arg and feeding it to the original function (first) arg.
  2. In lambda functions, %& can be used to insert all args in a collection

Resources

Tory Anderson avatar
Tory Anderson
Full-time Web App Engineer, Digital Humanist, Researcher, Computer Psychologist