Printing a nicely formatted plaintext table of data in Clojure
I use this fairly often while data-munging, when I want to quickly view a list of hash-maps of data in a simple table format. Usually this is coming out of database. Maybe someone will find it useful.
(defn table
"Given a seq of hash-maps, prints a plaintext table of the values of the hash-maps.
If passed a list of keys, displays only those keys. Otherwise displays all the
keys in the first hash-map in the seq."
([xs]
(table xs (keys (first xs))))
([xs ks]
(when (seq xs)
(let [f (fn [old-widths x]
(reduce (fn [new-widths k]
(let [length (inc (count (str (k x))))]
(if (> length (k new-widths 0))
(assoc new-widths k length)
new-widths)))
old-widths ks))
widths (reduce f {} (conj xs (zipmap ks ks)))
total-width (reduce + (vals widths))
format-string (str "~{"
(reduce #(str %1 "~" (%2 widths) "A") "" ks)
"~}~%")]
(cl-format true format-string (map str ks))
(cl-format true "~{~A~}~%" (repeat total-width \-))
(doseq [x xs]
(cl-format true format-string (map x ks)))))))
Then you can do this:
user> (def data [{:name "Brian" :job "Code monkey" :age 29}
{:name "Bob" :job "Janitor" :age 97}
{:name "Johnny McLongname" :job "None" :age 3}])
#'user/data
user> (table data)
:name :job :age
-----------------------------------
Brian Code monkey 29
Bob Janitor 97
Johnny McLongname None 3
nil
user> (table data [:age :name])
:age :name
-----------------------
29 Brian
97 Bob
3 Johnny McLongname
nil

2 Comments
This is neat, I'd totally use this if it were part of clojure.contrib.pprint
Thanks, this is very nice!
In order to try it in repl I had to import cl-format function from clojure.contrib.pprint:
(use '[clojure.contrib.pprint :only (cl-format)])Speak your Mind
Preview