3
0

More than 3 years have passed since last update.

Roman Numerals

Last updated at Posted at 2020-11-25

!Mac OS X-10.15.7 !ruby-2.7.1p83

Roman Numerals

講義ページリンク

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
3
0
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
3
0