RubyでFizzBuzz書いてみます
FizzBuzzとは?
- 1 から順に数を出力
- 3 で割り切れるならばFizzと出力
- 5 で割り切れるならばBuzzと出力
- 3 でも 5 でも割り切れる場合はFizzBuzzと出力
といった感じの要件を満たすプログラムです。
僕も新卒のOJTの際に書いてみてって言われてJava,JavaScriptで書いた覚えがあります。
現在仕事でRubyを使っているので、初心にもどって書いてみます。
まずはよく見かける形でコーディング
(1..100).each do |i|
if i % 15 == 0
puts "FizzBuzz"
elsif i % 3 == 0
puts "Fizz"
elsif i % 5 == 0
puts "Buzz"
else
puts i
end
end
ふむ
まずこの(1..100)
というRangeをターミナルから入力して自由に決めたい。
あとは、ちょっとずつメソッドに切り出してみよう。
加えてRubyのメソッドを存分に使う形で組み替えてみます。
ということで、うねうねした結果がこちら。
def console(args)
raise "argument is nil" if args.nil?
puts map_upto args.to_i
end
def map_upto(max)
(1..max).map { |n| fizzbuzz n }
end
def fizzbuzz_hash
{ 'fizz' => 3, 'buzz' => 5 }.sort_by { |_, v| v }.to_h
end
def fizzbuzz(n)
fizzbuzz_hash
.map { |str, val| str if (n % val).zero? }.join
.tap { |str| break str.empty? ? n : str }
end
if __FILE__ == $0
console ARGV[0]
end
初めとぜんぜん違う感じになりました。
一つずつ見ていきます。
def console(args)
raise "argument is nil" if args.nil?
puts map_upto args.to_i
end
ターミナル上に表示させるためのメソッド。
consoleというメソッドの引数にターミナル上での入力を渡す予定です。
このスクリプトを実行した際に、引数がなければ例外をあげます。
to_i で引数をStringからIntegerへ変更しmap_uptoメソッドへ渡しています。
※引数が文字列であった場合でもto_iすることで0となります。
続いてこちら
def map_upto(max)
(1..max).map { |n| fizzbuzz n }
end
maxが先程map_uptoメソッドへ渡された値となります。
もとのコードで(1..100)
となっている部分をmaxで置き換えた感じです。
1から順番に渡された引数までをnという値で順次fizzbuzzメソッドへ渡しています。
ここの戻り値がコンソール表示される値となります。
続いてこちら
def fizzbuzz_hash
{ 'fizz' => 3, 'buzz' => 5 }.sort_by { |_, v| v }.to_h
end
こちらは単に固定値のHashを返すだけのメソッドとなります。
※ @QUANON さんにアドバイス頂き修正しました。Hashの中身の数値でsortすることで
中身の順番に依存しなくなります。
続いてこちら
def fizzbuzz(n)
fizzbuzz_hash
.map { |str, val| str if (n % val).zero? }.join
.tap { |str| break str.empty? ? n : str }
end
まずfizzbuzz_hashが先程のHashとなります。
mapの部分で、引数で受け取ったnが3,5で余りなく割り切れるかどうかでstr、つまりHashのキーの部分を返しています。
mapは、表示する値を配列にして返すので、例えばnが15の場合、['fizz','buzz']という配列を返すことになります。
対して、余りが生じるような場合は、空の配列を返すことになります。
この配列をjoinすることで文字列として返すことが出来ます。
最後にtapを使うことで、文字列が空の場合は引数を、そうでない場合は文字列を返しています。
でもって最後
if __FILE__ == $0
console ARGV[0]
end
__FILE__
は現在実行しているプログラムのファイル名を表していて
$0は実行時に指定されたファイル名を相対パスで表しているそうです。
これらが等しい場合に、consoleメソッドに入力値を表すARGV[0]を渡しています。
では最後に結果を見てみます。
ruby fizz_buzz.rb 15
1
2
fizz
4
buzz
fizz
7
8
fizz
buzz
11
fizz
13
14
fizzbuzz
いけてるようですね。
時間があればテストも追加しようと思います。