public
Last active

Roman numeral kata in Clojure

  • Download Gist
roman.clj
Clojure
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41
(use 'clojure.test)
 
(def numerals {1 "I",
4 "IV",
5 "V",
9 "IX",
10 "X",
40 "XL",
50 "L",
90 "XC"
100 "C",
400 "CD",
500 "D",
900 "CM",
1000 "M"})
 
(defn to-roman [decimal]
(loop [[num & r :as nums] (reverse (sort (keys numerals)))
roman ""
d decimal]
(if num
(if (>= d num)
(recur nums (str roman (get numerals num)) (- d num))
(recur r roman d))
roman)))
 
(def digits (apply hash-map (mapcat reverse numerals)))
 
(defn from-roman [roman]
(loop [[c1 c2 & r] roman
d 0]
(if-let [num (and c2 (get digits (str c1 c2)))]
(recur r (+ d num))
(if-let [num (get digits (str c1))]
(recur (apply str c2 r) (+ d num))
d))))
 
(deftest test-round-trip
(let [nums (range 1 10000)
round-trip (map #(from-roman (to-roman %)) nums)]
(is (= nums round-trip))))

Please sign in to comment on this gist.

Something went wrong with that request. Please try again.