September 17, 2018

Just Juxt #34: Read Roman numerals (4clojure #92)

Clock

Roman numerals are easy to recognize, but not everyone knows all the rules necessary to work with them. Write a function to parse a Roman-numeral string and return the number it represents.

You can assume that the input will be well-formed, in upper-case, and follow the subtractive principle. You don't need to handle any numbers greater than MMMCMXCIX (3999), the largest number representable with ordinary letters.

(ns live.test
  (:require [cljs.test :refer-macros [deftest is testing run-tests]]))
  
(defn roman-numeral [s]
    (let [symbol-values {\I 1 \V 5
                         \X 10 \L 50
                         \C 100 \D 500
                         \M 1000}]
      (->>
        (partition-by identity s)
        (map (juxt first count))
        (partition-all 2 1)
        (map
          (fn [[[symbol cardinality] [next-symbol _]]]
            (let [value (symbol-values symbol)]
              (* cardinality value
                (if (and next-symbol
                         (< value (symbol-values next-symbol)))
                  -1 1)))))
        (apply +))))

(deftest roman-numeral-test
  (is (= 14 (roman-numeral "XIV")))
  (is (= 827 (roman-numeral "DCCCXXVII")))
  (is (= 3999 (roman-numeral "MMMCMXCIX")))
  (is (= 48 (roman-numeral "XLVIII"))))
  
(run-tests)
Tags: coding exercises KLIPSE 4clojure Cryogen juxt