Roman Numerals

\![Mac OS X-10.15.7](<https://img.shields.io/badge/MacOSX-10.15.7-brightgreen>) \![ruby-2.7.1p83](<https://img.shields.io/badge/ruby-2.7.1p83-brightgreen>) 


# Roman Numerals


## 講義ページリンク

[roman numerals](https://qiita.com/daddygongon/items/2d0a73a51ddab2d9da1b)


## 課題

アラビア数字を受け取って，それに対応した[ローマ数字](https://ja.wikipedia.org/wiki/%E3%83%AD%E3%83%BC%E3%83%9E%E6%95%B0%E5%AD%97)を返すプログラムの作成ついでに整数(Integer)クラスを拡張する


## アラビア数字からローマ数字への変換方法

\\\*追記<span class="timestamp-wrapper"><span class="timestamp">&lt;2020-11-26 Thu&gt;</span></span>

-   扱う数字は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)


## 解答例

\\\*追記<span class="timestamp-wrapper"><span class="timestamp">&lt;2020-11-26 Thu&gt;</span></span>

-   上記の変換方法の追記のとおりに書いたコードが以下のもの

```ruby
#!/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

-   下のコードは以前のもの一応残しときます

追記終わり

```ruby
#!/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したらなぜか解答例のソースコードのインデントがおかしくなってる&#x2026;



------
 - **source** ~/multiscalesim_toku/grad_members_20f/members/lynd2299/roman_numerals.org