Skip to content

Instantly share code, notes, and snippets.

@yenda
Last active February 26, 2016 15:28
Show Gist options
  • Save yenda/116dca46c5a6ad984f99 to your computer and use it in GitHub Desktop.
Save yenda/116dca46c5a6ad984f99 to your computer and use it in GitHub Desktop.
Zalando interview
;; I had a really hard time programming and thinking in Clojure within a raw text editor and under stress,
;; so I took gave a new try to the problem using the repl and my usual editor (emacs) for a second shot
;; using the repl helped me quickly discard poor solutions and fix small quirks.
;; Here is what I came up with :
;; First I get the headers with the max width of each columns and print them, the way I started it during the interview
;; Then I completed each row with the missing keys using a sorted map and adding the whitespaces
;; Then I printed all the rows
;; There still could be some refactoring to minimize recalculation of some of the structures but it is suppose to be a 30 min exercice
(def input [{:foo "b" :b "bar"}, {:zal "ando" :b "x"}])
;; PPRINT THE HEADERS
(defn headers
"Get a set of the headers"
[input]
(reduce #(into %1 (keys %2)) #{} input))
(defn headers-map
"Get a sorted map of the headers with empty lists as values"
[headers]
(->> headers
(reduce #(assoc %1 %2 '()) {})
(into (sorted-map))))
(defn headers-map-list
"Get a sorted map of the headers with empty strings as values"
[headers]
(->> headers
(reduce #(assoc %1 %2 "") {})
(into (sorted-map))))
(defn sort-row
"Add the row of attributes to the sorted input maps"
[sorted-input row]
(reduce #(update-in %1 [(key %2)] conj (val %2)) sorted-input row))
(defn sort-attributes-by-header
"Sort all the attributes in a single map with headers as keys"
[input]
(let [headers-map (-> input headers headers-map)]
(reduce #(sort-row %1 %2) headers-map input)))
(defn max-length
"Returns a map with headers as keys and max length of a column as value"
[input]
(->> input
sort-attributes-by-header
(reduce #(assoc %1 (key %2) (max (count (name (key %2)))
(apply max (map count (val %2))))) {})))
(defn header-whitespaces
"Take a header/max-length pair and return a string of whitespaces to fill a header"
[header]
(let [whitespaces (- (second header) (count (name (first header))))]
(if (> 0 whitespaces)
" "
(apply str " " (take whitespaces (repeat " ")) ))))
(defn headers->str
"Returns the headers as a string"
[input]
(let [max-length (max-length input)
headers (map name (keys max-length))
whitespaces (map header-whitespaces max-length)
to-print (clojure.string/join (interleave headers whitespaces))]
(str to-print "\n" (apply str (take (dec (count to-print)) (repeat "-"))) "\n")))
;; PPRINT THE ATTRIBUTES
(defn attributes
"Returns an ordered map similar to input but with the missing columns"
[input]
(let [headers-map (-> input headers headers-map-list)]
(map #(merge headers-map (into (sorted-map) %)) input)))
(defn attribute->str
"Returns an attribute as a string"
[attr max-length]
(let [length (count attr)]
(if (< length max-length)
(apply str attr (take (- max-length length) (repeat " ")))
attr)))
(defn row->str
"Returns a row as a string"
[row max-length]
(->> (map #(attribute->str (val %) ((key %) max-length)) row)
(clojure.string/join " ")))
(defn attributes->str
[input]
(->> (map #(row->str %1 (max-length input)) (attributes input))
(clojure.string/join "\n")))
(defn pprint-input
"Pretty print headers and attributes"
[input]
(print (headers->str input))
(print (attributes->str input)))
(pprint-input input)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment