# Need help on a program

Stuck on this exercise from a book:
Old-school Roman numerals. In the early days of Roman numerals,
the Romans didnâ€™t bother with any of this new-fangled subtraction
â€œIXâ€ nonsense. No sir, it was straight addition, biggest to littlestâ€”
so 9 was written â€œVIIII,â€ and so on. Write a method that, when
passed an integer between 1 and 3000 (or so), returns a string
containing the proper old-school Roman numeral. In other words,
old_roman_numeral 4 should return ‘IIII’. Make sure to test
your method on a bunch of different numbers.
For reference, these are the values of the letters used:
I =1 V =5 X = 10 L = 50
C = 100 D = 500 M = 1000

Suggestions on a soloution?

Suggestions on a soloution?
There’s one in the Ruby Cookbook, by O’Reilly. I am sure there would be
some on Google, too. I even think I recall a RubyQuiz on this topic.

Christopher L. wrote:

I =1 V =5 X = 10 L = 50
C = 100 D = 500 M = 1000

Suggestions on a soloution?

Posted via http://www.ruby-forum.com/.

class Integer
def to_roman
“I =1 V =5 X = 10 L = 50
C = 100 D = 500 M = 1000”.
scan( / ([A-Z]) \s = \s (\d+) /x ).
map{|letter,val| [ letter, val.to_i ] }.
sort_by{|a| -a.last}.
inject( [ “”, self ] ){|roman, pair|
[ roman.first + pair.first * (roman.last / pair.last),
roman.last % pair.last ] }.
first
end
end

On 12/9/06, Christopher L. [email protected] wrote:

I =1 V =5 X = 10 L = 50
C = 100 D = 500 M = 1000

Suggestions on a soloution?

1. skeleton (I’ll use test/unit, as it’s easier to check the results)

require ‘test/unit’

def to_roman(int)

# here comes the code

end

class TestToRoman < Test::Unit::TestCase

# check the base digits

def test_roman_digits
assert_equal ‘I’, to_roman(1)
assert_equal ‘V’, to_roman(5)
assert_equal ‘X’, to_roman(10)
assert_equal ‘L’, to_roman(50)
assert_equal ‘C’, to_roman(100)
assert_equal ‘D’, to_roman(500)
assert_equal ‘M’, to_roman(1000)
end

def test_roman_more
assert_equal ‘I’, to_roman(1)
assert_equal ‘II’, to_roman(2)
assert_equal ‘III’, to_roman(3)
assert_equal ‘IIII’, to_roman(4)

``````   assert_equal 'VI', to_roman(6)
assert_equal 'VII', to_roman(7)
assert_equal 'VIII', to_roman(8)
assert_equal 'VIIII', to_roman(9)

assert_equal 'MDCCCCLXXXVIIII', to_roman(1989)
``````

end
end

1. to the actual solution:
(you’ll be creating the number left-to-right)

find largest digit less than the number. subtract its value from the
number, add the digit to the result
. repeat until the digit is larger
than the remainder. if there’s anything left, choose the next digit.

in fact, the text between the stars is the simplest/most generic
algorithm. the following things are just an optimisation.

The actual ruby code I’ll leave to you. First do anything that works
(use the test above to check, and add your own ones), no matter how
ugly it is. Then post your code, and somebody (be it me or anybody
else) will suggest you improvements.

1. a bit of rubyism:

def to_roman(int)

end

and calling as to_roman(123) you can extend the integers themselves:

class Integer
def to_roman

# use self insted of int parameter

end
end

and call as 123.to_roman - it’s nicer.

class Integer
def to_roman
Hash[“M”, 1000, “D”, 500, “C”, 100, “L”, 50, “X”, 10, “V”, 5, “I”,
1].sort_by{|a| -a.last}.inject( [ “”, self ] ){|roman, pair|
[ (pair.last - roman.last ==1 )? roman.first+“I”+pair.first :
roman.first + pair.first * (roman.last / pair.last),
roman.last % pair.last ] }.
first
end
end

I noticed that your code is partly wrong since it will output IIII for
4 and so on , I have modified it a little bit , but I have not checked
the result

Regards
On 12/9/06, William J. [email protected] wrote:

For reference, these are the values of the letters used:
"I =1 V =5 X = 10 L = 50

Chá»‰ cÃ³ lÃ½ trÃ­ cá»§a báº£n thÃ¢n má»›i soi sÃ¡ng Ä‘Æ°á»£c sá»± tháº­t.“CÃ¡i Ä‘áº¹p Ä‘áº½ nháº¥t
mÃ chÃºng ta cÃ³ thá»ƒ tráº£i nghiá»‡m Ä‘Æ°á»£c lÃ cÃ¡i bÃ­ áº©n. ÄÃ³ lÃ cáº£m thá»©c ná»n
táº£ng trong cÃ¡i nÃ´i cá»§a nghá»‡ thuáº­t vÃ khoa há»c chÃ¢n chÃ­nh. Káº» nÃ o khÃ´ng
biáº¿t Ä‘áº¿n nÃ³, khÃ´ng cÃ²n kháº£ nÄƒng ngáº¡c nhiÃªn hay kinh ngáº¡c, káº» Ä‘Ã³ coi
nhÆ° Ä‘Ã£ cháº¿t, Ä‘Ã£ táº¯t rá»¥i lá»­a sá»‘ng trong máº¯t mÃ¬nh”“Das SchÃ¶nste, was wir
erleben kÃ¶nnen, ist das Geheimnisvolle. Es ist das GrundgefÃ¼hl, das an
der Wiege von wahrer Kunst und Wissenschaft steht. Wer es nicht kennt
und sich nicht mehr wundern, nicht mehr staunen kann, der ist
sozusagen tot und sein Auge erloschen.”“The fairest thing we can
experience is the mysterious. It is the fundamental emotion which
stands at the cradle of true art and true science. He who knows it not
and can no longer wonder, no longer feel amazement, is as good as
dead, his eyelight has been extinct.”

#!/usr/bin/env ruby
@data = [
[
“M” , 1000],
[“CM” , 900],
[“D” , 500],
“CD” , 400],
[
[“C” , 100],
[
“XC” , 90],
“L” , 50],
[
“XL” , 40],
[
[“X” , 10],
[“IX” , 9],
“V” , 5],
[
[
“IV” , 4],
“I” , 1]
[
]
@roman = %r{^[CDILMVX]\$}
@arabic = %r{^[0-9]
\$}
def to_roman(num)
“”
for key, value in @data
count, num = num.divmod(value)
end
end
def
to_arabic(rom)
for key, value in @data
while rom.index(key) == 0
rom.slice!(key)
end
end