!Mac OS X-10.15.7 !ruby-2.7.1p83
Roman Numerals
講義ページリンク
課題
アラビア数字を受け取って,それに対応したローマ数字を返すプログラムの作成ついでに整数(Integer)クラスを拡張する
アラビア数字からローマ数字への変換方法
\*追記<2020-11-26 Thu>
- 扱う数字は4000未満なのでハッシュを使ったほうが簡潔に書ける
- 4(IV)と9(IX)もハッシュに登録しておけば剰余を使って簡単にローマ数字が作れる
- 過去に書いたやつは一応引用にしておきます
追記終わり
- 各桁を表すのに使用する文字は,1,5,次の桁の1(10)を表す3つ
- 例えば1桁目では(I(1), V(5), X(10)), 2桁目では10倍した(X(10), L(50), C(100))を用いる
- 各桁では,その桁の値に応じて次のルールに従って文字を並べる
- 1~3: 1の文字を数字分並べる(III)
- 4: 5の文字の左に1の文字(IV)
- 5: 5の文字(V)
- 6~8: 5の文字の右に,数字と5の差の分だけ1の文字を並べる(VIII)
- 9: 次の桁の1の文字の左に1の文字(IX)
- 各桁の文字を並べる(439 => CDXXXIX)
解答例
\*追記<2020-11-26 Thu>
- 上記の変換方法の追記のとおりに書いたコードが以下のもの
#!/usr/bin/env ruby
# frozen_string_literal: true
class Integer
def to_roman
return unless between?(1, 3999)
roman_map = { 1 => 'I', 4 => 'IV', 5 => 'V', 9 => 'IX', 10 => 'X', 40 => 'XL', 50 => 'L', 90 => 'XC', 100 => 'C', 400 => 'CD', 500 => 'D', 900 => 'CM', 1000 => 'M' }
num = self
roman = roman_map.reverse_each.map do |key, value|
times = num / key
num %= key
value * times
end
roman.join
end
end
test_data = [1, 2, 4, 5, 6, 9, 10, 11, 14, 15, 19, 38, 42, 49, 51, 97, 99, 439, 483, 499, 732, 961, 999, 1999, 4000]
test_data.each do |n|
puts "#{n}\t#{n.to_roman}"
end
出力
> ruby roman_numerals.rb
1 I
2 II
4 IV
5 V
6 VI
9 IX
10 X
11 XI
14 XIV
15 XV
19 XIX
38 XXXVIII
42 XLII
49 XLIX
51 LI
97 XCVII
99 XCIX
439 CDXXXIX
483 CDLXXXIII
499 CDXCIX
732 DCCXXXII
961 CMLXI
999 CMXCIX
1999 MCMXCIX
4000
- 下のコードは以前のもの一応残しときます
追記終わり
#!/usr/bin/env ruby
# frozen_string_literal: true
class Integer
def to_roman
if !between?(1, 3999)
puts "#{self} is not supported in #{__method__}."
exit
else
roman = []
roman_symbols = %w[I V X L C D M]
digits.to_a.each_with_index do |n, i|
ivx = roman_symbols.slice(2 * i, 3)
case n
when 1..3 then roman.push(ivx[0] * n)
when 4 then roman.push(ivx[0] + ivx[1])
when 5 then roman.push(ivx[1])
when 6..8 then roman.push(ivx[1] + (ivx[0] * (n - 5)))
when 9 then roman.push(ivx[0] + ivx[2])
end
end
end
roman.reverse.join
end
end
test_data = [1, 2, 4, 5, 6, 9, 10, 11, 14, 15, 19, 38, 42, 49, 51, 97, 99, 439, 483, 499, 732, 961, 999, 1999, 4000]
test_data.each do |n|
puts "#{n}\t#{n.to_roman}"
end
出力
> ruby roman_numerals.rb
1 I
2 II
4 IV
5 V
6 VI
9 IX
10 X
11 XI
14 XIV
15 XV
19 XIX
38 XXXVIII
42 XLII
49 XLIX
51 LI
97 XCVII
99 XCIX
439 CDXXXIX
483 CDLXXXIII
499 CDXCIX
732 DCCXXXII
961 CMLXI
999 CMXCIX
1999 MCMXCIX
4000 is not supported in to_roman.
NOTE
- Integerクラス内で
self.digits
にアクセスすると,自身の各桁の値を取得できる- 上記のコードでは
self.
はrubocopに削除されたのでいらないのかも
- 上記のコードでは
- 更に
.to_a
で配列として取得できる - 配列に対して
.each_with_index
でpythonのenumerateみたいに数値とインデックスを取得できる - 上記のコードのようにするとハッシュを作成できる
-
.each
のあとに.map
を使うとmap関数的なのが使えて,新しい配列が作れる - あとqiitaにpostしたらなぜか解答例のソースコードのインデントがおかしくなってる…
- source ~/multiscalesim_toku/grad_members_20f/members/lynd2299/roman_numerals.org