Skip to content

Instantly share code, notes, and snippets.

@mrbuk
Last active November 15, 2015 15:47
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mrbuk/54d9d835a312b65a705a to your computer and use it in GitHub Desktop.
Save mrbuk/54d9d835a312b65a705a to your computer and use it in GitHub Desktop.
Solution for 4clojure problem 92
;;
;; first not so idiomatic approach to the problem to convert roman numerals to decimal.
;;
(fn roman-to-dec [s]
(let [default-f (fn [last acc]
(+ acc))
prefixed-f (fn [prefixes]
(fn [last acc]
(if (some #(= % last) prefixes)
(- acc)
(+ acc))))
rules {\M { :acc 1000 :f default-f }
\D { :acc 500 :f default-f }
\C { :acc 100 :f (prefixed-f [\M \D]) }
\L { :acc 50 :f default-f }
\X { :acc 10 :f (prefixed-f [\C \L]) }
\V { :acc 5 :f default-f }
\I { :acc 1 :f (prefixed-f [\X \V]) }}]
(->> (reverse s) ;; easier to process number in revered order
(map #(assoc (rules %) :type %)) ;; use rules to map token -> fn
;; calculate the value for each digit. we use reduce as each value can depend
;; on his successor (CM -> MC -> [ 1000 -100 ])
(reductions
(fn [x y]
(let [last-type (x :type)
current-type (y :type)
acc (y :acc)
f (y :f)
result (f last-type acc)]
(assoc {} :result result :type current-type)))
;; initial value is 0 and no type
{:result 0 :type nil})
;; extract the results only
(map #(:result %))
;; add up the resulting numbers
(reduce +))))
;;
;; a more idiomatic solution -> http://rosettacode.org/wiki/Roman_numerals/Decode#Clojure
;;
(fn ro2ar [r]
(->> (reverse r)
(replace (zipmap "MDCLXVI" [1000 500 100 50 10 5 1]))
(partition-by identity)
(map (partial apply +))
(reduce #(if (< %1 %2) (+ %1 %2) (- %1 %2)))))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment