# Need help on a program

**URL:** <https://rubytalk.org/t/need-help-on-a-program/33599>\
**Category:** ruby-talk\
**Created:** [9 December 2006 11:29 UTC](https://rubytalk.org/t/need-help-on-a-program/33599 "2006-12-09T11:29:13Z")\
**Posts on this page:** 6\
**Page:** 1

<div class="post-metadata">

**Author:** ![Christopher\_Latif](https://avatars.discourse-cdn.com/v4/letter/c/97f17d/32.png) [@Christopher\_Latif](https://rubytalk.org/u/Christopher_Latif)\
**Post date:** [9 December 2006 11:29 UTC](https://rubytalk.org/t/need-help-on-a-program/33599/1 "2006-12-09T11:29:13Z")

</div>

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?

> **···**
>
> --  
> Posted via [http://www.ruby-forum.com/](http://www.ruby-forum.com/).

---

<div class="post-metadata">

**Author:** ![Edwin\_Fine](https://avatars.discourse-cdn.com/v4/letter/e/b3f665/32.png) [@Edwin\_Fine](https://rubytalk.org/u/Edwin_Fine)\
**Post date:** [9 December 2006 13:03 UTC](https://rubytalk.org/t/need-help-on-a-program/33599/2 "2006-12-09T13:03:27Z")

</div>

> 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.

> **···**
>
> --  
> Posted via [http://www.ruby-forum.com/\](http://www.ruby-forum.com/%5C).

---

<div class="post-metadata">

**Author:** ![Jan\_Svitok](https://avatars.discourse-cdn.com/v4/letter/j/cab0a1/32.png) [@Jan\_Svitok](https://rubytalk.org/u/Jan_Svitok)\
**Post date:** [9 December 2006 13:04 UTC](https://rubytalk.org/t/need-help-on-a-program/33599/3 "2006-12-09T13:04:50Z")

</div>

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

require 'test/unit'

def to\_roman(int)  
&nbsp;&nbsp;&nbsp;# here comes the code  
end

class TestToRoman \< Test::Unit::TestCase  
&nbsp;&nbsp;&nbsp;# check the base digits  
&nbsp;&nbsp;&nbsp;def test\_roman\_digits  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;assert\_equal 'I', to\_roman(1)  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;assert\_equal 'V', to\_roman(5)  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;assert\_equal 'X', to\_roman(10)  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;assert\_equal 'L', to\_roman(50)  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;assert\_equal 'C', to\_roman(100)  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;assert\_equal 'D', to\_roman(500)  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;assert\_equal 'M', to\_roman(1000)  
&nbsp;&nbsp;&nbsp;end

&nbsp;&nbsp;&nbsp;def test\_roman\_more  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;assert\_equal 'I', to\_roman(1)  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;assert\_equal 'II', to\_roman(2)  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;assert\_equal 'III', to\_roman(3)  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;assert\_equal 'IIII', to\_roman(4)

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;assert\_equal 'VI', to\_roman(6)  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;assert\_equal 'VII', to\_roman(7)  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;assert\_equal 'VIII', to\_roman(8)  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;assert\_equal 'VIIII', to\_roman(9)

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;assert\_equal 'MDCCCCLXXXVIIII', to\_roman(1989)  
&nbsp;&nbsp;&nbsp;end  
end

2. 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.

3. a bit of rubyism:

instead of  
def to\_roman(int)  
&nbsp;&nbsp;&nbsp;...  
end

and calling as to\_roman(123) you can extend the integers themselves:

class Integer  
&nbsp;&nbsp;&nbsp;def to\_roman  
&nbsp;&nbsp;&nbsp;# use self insted of int parameter  
&nbsp;&nbsp;&nbsp;end  
end

and call as 123.to\_roman - it's nicer.

> **···**
>
> On 12/9/06, Christopher Latif \<christopherl@bredband.net\> wrote:
> 
> > 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?

---

<div class="post-metadata">

**Author:** ![W\_James](https://avatars.discourse-cdn.com/v4/letter/w/e274bd/32.png) [@W\_James](https://rubytalk.org/u/W_James)\
**Post date:** [9 December 2006 16:50 UTC](https://rubytalk.org/t/need-help-on-a-program/33599/4 "2006-12-09T16:50:06Z")

</div>

Christopher Latif wrote:

> 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?
> 
> --  
> Posted via [http://www.ruby-forum.com/\](http://www.ruby-forum.com/%5C).

class Integer  
&nbsp;&nbsp;def to\_roman  
&nbsp;&nbsp;&nbsp;&nbsp;"I =1 V =5 X = 10 L = 50  
&nbsp;&nbsp;&nbsp;&nbsp;C = 100 D = 500 M = 1000".  
&nbsp;&nbsp;&nbsp;&nbsp;scan( / ([A-Z]) \s \*= \s\* (\d+) /x ).  
&nbsp;&nbsp;&nbsp;&nbsp;map{|letter,val| [letter, val.to\_i] }.  
&nbsp;&nbsp;&nbsp;&nbsp;sort\_by{|a| -a.last}.  
&nbsp;&nbsp;&nbsp;&nbsp;inject( ["", self] ){|roman, pair|  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[ roman.first + pair.first \* (roman.last / pair.last),  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;roman.last % pair.last ] }.  
&nbsp;&nbsp;&nbsp;&nbsp;first  
&nbsp;&nbsp;end  
end

---

<div class="post-metadata">

**Author:** ![Hung\_Dao](https://avatars.discourse-cdn.com/v4/letter/h/7bcc69/32.png) [@Hung\_Dao](https://rubytalk.org/u/Hung_Dao)\
**Post date:** [10 December 2006 11:53 UTC](https://rubytalk.org/t/need-help-on-a-program/33599/5 "2006-12-10T11:53:30Z")

</div>

class Integer  
def to\_roman  
&nbsp;&nbsp;&nbsp;Hash["M", 1000, "D", 500, "C", 100, "L", 50, "X", 10, "V", 5, "I",  
1].sort\_by{|a| -a.last}.inject( ["", self] ){|roman, pair|  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[ (pair.last - roman.last ==1 )? roman.first+"I"+pair.first :  
roman.first + pair.first \* (roman.last / pair.last),  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;roman.last % pair.last ] }.  
&nbsp;&nbsp;&nbsp;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 James \<w\_a\_x\_man@yahoo.com\> wrote:
> 
> > Christopher Latif wrote:  
> > \> 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?  
> > \>  
> > \> --  
> > \> Posted via [http://www.ruby-forum.com/\](http://www.ruby-forum.com/%5C).
> > 
> > class Integer  
> > &nbsp;&nbsp;def to\_roman  
> > &nbsp;&nbsp;&nbsp;&nbsp;"I =1 V =5 X = 10 L = 50  
> > &nbsp;&nbsp;&nbsp;&nbsp;C = 100 D = 500 M = 1000".  
> > &nbsp;&nbsp;&nbsp;&nbsp;scan( / ([A-Z]) \s \*= \s\* (\d+) /x ).  
> > &nbsp;&nbsp;&nbsp;&nbsp;map{|letter,val| [letter, val.to\_i] }.  
> > &nbsp;&nbsp;&nbsp;&nbsp;sort\_by{|a| -a.last}.  
> > &nbsp;&nbsp;&nbsp;&nbsp;inject( ["", self] ){|roman, pair|  
> > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[ roman.first + pair.first \* (roman.last / pair.last),  
> > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;roman.last % pair.last ] }.  
> > &nbsp;&nbsp;&nbsp;&nbsp;first  
> > &nbsp;&nbsp;end  
> > end
> 
> --  
> 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."

---

<div class="post-metadata">

**Author:** ![Hung\_Dao](https://avatars.discourse-cdn.com/v4/letter/h/7bcc69/32.png) [@Hung\_Dao](https://rubytalk.org/u/Hung_Dao)\
**Post date:** [10 December 2006 14:15 UTC](https://rubytalk.org/t/need-help-on-a-program/33599/6 "2006-12-10T14:15:15Z")

</div>

#!/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)  
""  
reply =  
for key, value in @data  
count, num = num.divmod(value)  
reply \<\< (key \* count)  
end  
reply  
end  
def  
to\_arabic(rom)  
reply = 0  
for key, value in @data  
while rom.index(key) == 0  
reply += value  
rom.slice!(key)  
end  
reply  
end  
$stdin.each do |line|  
case line  
when @roman  
puts to\_arabic(line)  
when @arabic  
puts to\_roman(line.to\_i)  
end

> **···**
>
> ----  
> Another solution from the pragmatic book : best quiz
