Skip to content

Instantly share code, notes, and snippets.

@guilespi
Last active December 31, 2015 19:09
Show Gist options
  • Save guilespi/8032154 to your computer and use it in GitHub Desktop.
Save guilespi/8032154 to your computer and use it in GitHub Desktop.
decimal to roman
(def conv-table (sorted-map 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 update-result
"Given a current sequence with a result appends
n times symbols s"
[result n s]
(if (> n 0)
(concat result (repeat n s))
result))
(defn convert
"Actual iteration over symbol conversion table."
[seed]
(-> (reduce (fn [[number result] [roman sym]]
[(rem number roman)
(update-result result (quot number roman) sym)])
[seed []]
(reverse conv-table))
second))
(defn large-numeral
"Given a decimal number converts to wrapped roman
numeral, meaning * 1000.
i.e. 7000 => |VII|"
[n]
(concat [:|] (convert n) [:|]))
(defn dec->roman
"Given a decimal number converts to roman numerals"
[number]
{:pre [(>= number 0)]}
(let [prefix (when (>= number 5000)
(large-numeral (quot number 1000)))
seed (if prefix
(rem number 1000)
number)
result (convert seed)]
(clojure.string/join (map name (concat prefix result)))))
;;tests
(deftest test-update
(is (= [:I] (update-result [] 1 :I)))
(is (= [] (update-result [] 0 :I)))
(is (= [:I :V :V] (update-result [:I] 2 :V))))
(deftest large-numeral
(is (= [:| :V :|] (large-numeral 5))))
(deftest test-convert
(is (= "I" (dec->roman 1)))
(is (= "IV" (dec->roman 4)))
(is (= "V" (dec->roman 5)))
(is (= "XC" (dec->roman 90)))
(is (= "L" (dec->roman 50)))
(is (= "MCMLXXXVII" (dec->roman 1987)))
(is (= "CDLXVII" (dec->roman 467)))
(is (= "|V|" (dec->roman 5000)))
(is (= "|VII|DCCCLXXXVIII" (dec->roman 7888)))
(is (thrown? AssertionError (dec->roman -1))))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment