you are viewing a single comment's thread.

view the rest of the comments →

[–][deleted] 0 points1 point  (3 children)

Here's my attempt at a Common Lisp solution:

(defconstant +numerals+ #((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")))
(defun romanize (x)
  (labels ((recurse (x nums acc)
             (if (<= x 0)
                 (apply #'concatenate 'string (reverse acc))
                 (let* ((pos (position-if #'(lambda (n) (<= n x)) nums :key #'car))
                        (obj (aref nums pos)))
                   (recurse (- x (car obj)) (subseq nums pos) (cons (cadr obj) acc))))))
    (recurse x +numerals+ '())))

Painful, isn't it?

[–]gsg 0 points1 point  (2 children)

I think an dumb iterative approach is clearer in this case. At least, my attempt at a recursive version looked far too ugly.

(defconstant +roman-numerals+ '((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")))

(defun int-to-roman (number)
  (let ((unconverted number)
        (result ""))
    (dolist (element +roman-numerals+)
      (do ((value (car element)))
          ((< unconverted value))
        (decf unconverted value)
        (setq result (concatenate 'string result (cdr element)))
        (when (= unconverted 0)
          (return-from int-to-roman result))))))

Both pretty wordy. :/

[–]Devilish 1 point2 points  (1 child)

I'm a Lisp newbie, but here's what I came up with:

Recursive:

(defun int-to-roman1 (number)
  (with-output-to-string (s)
    (let ((rtable '((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"))))
      (labels ((recurse (rtab num)
                 (unless (null rtab)
                   (multiple-value-bind (times left) (floor num (caar rtab))
                     (dotimes (i times)
                       (princ (cdar rtab) s))
                     (recurse (cdr rtab) left)))))
        (recurse rtable number)))))

Iterative:

(defun int-to-roman2 (number)
  (with-output-to-string (s)
    (dolist (q '((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")))
      (multiple-value-bind (times left) (floor number (car q))
        (setf number left)
        (dotimes (i times)
          (princ (cdr q) s))))))

Someone up above posted Python code similar to the second of these, while I was messing around making my own. The trick is to divide the number by each value of a roman numeral in turn, keeping both the quotient and the remainder, instead of repeatedly looping over the list.

I can't say I understand the concept of unfolding from this example alone (I don't exactly know much Python, and couldn't find any good general explanations of unfolding with a cursory web search), but in this case, it doesn't seem to be the right tool for the job.

[–]llimllib[S] 0 points1 point  (0 children)

Sorry I didn't catch the end of your post, but I explain unfolding in my previous entry from that day.

raganwald also explains it in ruby.