Instantly share code, notes, and snippets.

# miner/roman.clj

Created Aug 6, 2012
Roman Numerals
 (ns miner.roman (:require [clojure.test :refer :all])) ;; inspired by ;; http://www.jayway.com/2012/08/04/a-decimal-to-roman-numeral-converter-in-just-a-few-lines/ (def roman-map {1000 "M" 900 "CM" 500 "D" 400 "CD" 100 "C" 90 "XC" 50 "L" 40 "XL" 10 "X" 9 "IX" 5 "V" 4 "IV" 1 "I"}) (def roman-bases (sort > (keys roman-map))) (defn roman-addends [n] {:pre [(< 0 n 4000)]} (loop [n n bases roman-bases addends []] (if (zero? n) addends (let [base (first bases)] (if (>= n base) (recur (- n base) bases (conj addends base)) (recur n (rest bases) addends)))))) (defn roman [n] (apply str (map roman-map (roman-addends n)))) ;; clojure.pprint/cl-format works but is slow (defn roman-cl [n] (clojure.pprint/cl-format nil "~@R" n)) (deftest roman-4k (doseq [n (range 1 4000)] (is (= (roman-cl n) (roman n))))) (def inv-roman-char-map {\M 1000 \D 500 \C 100 \L 50 \X 10 \V 5 \I 1}) (defn roman-values-seq [rn] (let [vs (rseq (conj (mapv inv-roman-char-map rn) 0))] ;; going in reverse order is easier, ;; padded zero to simplify prev (map (fn [v prev] (if (>= v prev) v (- v))) (rest vs) vs))) (defn parse-roman [rn] (reduce + (roman-values-seq rn))) (deftest parse-roman-test (doseq [n (range 1 4000)] (is (= n (parse-roman (roman n))))))
Owner Author

### miner commented May 23, 2014

 here's a faster version: https://gist.github.com/miner/9ff494e7cd0c9af64d03