LoginSignup
15
2

More than 3 years have passed since last update.

roman numerals(hashで簡潔化してみた)

Posted at

roman numerals

問題

アラビア数字(arabic numerals)を受け取って,ローマ数字(roman numerals)を返すmethodを書きなさい.

各ローマ数字は以下のように対応する.

roman num arabic num
I 1
V 5
X 10
L 50
C 100
D 500
M 1000

解法

基本的にローマ数字各種に対応するアラビア数字で順に割っていくのが正攻法だろう.ただし,ローマ数字はアラビア数字における 4 や 9 においては少し特殊な挙動をする.計算式でうまいことやろうとするとif 文を乱用しそう.

今回は簡潔で美しいプログラムにすべく,アラビア数字各桁における 4 や 9 についてはあらかじめ配列に登録しておく.とはいったものの配列を用意するとなるとローマ数字とアラビア数字の 2 つ配列を用意しないといけない.これでは簡潔で美しいプログラムではなくなってしまう.

そこで授業内では触れられていないが,Ruby ならではの便利な hash を活用する.hash を簡単に説明すると Python でいう辞書型である.2 つの配列に対し,不規則だが対応関係があるものについては hash と each を活用すれば簡潔なプログラムにできる.プログラミングスクールのメンターをしていたときに学んだことがこんなところで活かせるとは.

2 つの配列を Hash で

配列を用いたら

arabic_value = [1000,900,500,400,100,90,50,40,10,9,5,4,1]
roman_value = ["M","CM","D","CD","C","XC","L","XL","X","IX","V","IV","I"]

と 2 行になってしまうところを,ハッシュを用いれば

value_sets = {"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"}

こんな感じで 1 行にでき,視覚的にも直感で理解しやすくなる.

実装

それでは,hash を用いてアラビア数字をローマ数字に変換するメソッド to_roman を実装してみる.hash の key は アラビア数字なので,先頭から順に key で割っていき,商の回数分ローマ数字である value を代入すれば良い.これを hash の先頭から each で繰り返せば良いので,プログラムは以下のようになる.

def to_roman(num)
  str = ""
  value_sets = {"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"}
  value_sets.each do |arabic,roman|
    quotient = num/arabic.to_i
    num = num%arabic.to_i
    str << roman*quotient
  end
  str
end

puts to_roman(ARGV[0].to_i)

想像以上に短いプログラムにできた.

発展問題

Integer class を拡張して,

999.to_roman #=>CMXCIX

のように実行することで,ローマ数字を返すようにしたい.

ここまできたらもう簡単.

実装

こんな感じ.

class Integer
  def to_roman
    num = self
    str = ""
    value_sets = {"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"}
    value_sets.each do |arabic,roman|
      quotient = num/arabic.to_i
      num = num%arabic.to_i
      str << roman*quotient
    end
    str
  end
end

puts ARGV[0].to_i.to_roman

動作確認

忘れずに動作確認しておく.

$ ruby roman_numerals.rb 23 
XXIII

$ ruby roman_numerals.rb 169
CLXIX

$ ruby roman_numerals.rb 1997
MCMXCVII

$ ruby roman_numerals.rb 2020 
MMXX

問題なさそう.

参考ページ

今回参考にしたページはこちら.roman numerals


  • source ~/grad_members_20f/members/e79a93e5b7b1/posts/class/roman_numerals.org
15
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
15
2