Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
Help us understand the problem. What is going on with this article?

RubyでFizzBuzz書いてみた

More than 3 years have passed since last update.

RubyでFizzBuzz書いてみます

FizzBuzzとは?

  • 1 から順に数を出力
  • 3 で割り切れるならばFizzと出力
  • 5 で割り切れるならばBuzzと出力
  • 3 でも 5 でも割り切れる場合はFizzBuzzと出力

といった感じの要件を満たすプログラムです。
僕も新卒のOJTの際に書いてみてって言われてJava,JavaScriptで書いた覚えがあります。

現在仕事でRubyを使っているので、初心にもどって書いてみます。
まずはよく見かける形でコーディング

fizz_buzz.rb
(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のメソッドを存分に使う形で組み替えてみます。

ということで、うねうねした結果がこちら。

fizz_buzz.rb
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

初めとぜんぜん違う感じになりました。
一つずつ見ていきます。

fizz_buzz.rb
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となります。

続いてこちら

fizz_buzz.rb
def map_upto(max)
  (1..max).map { |n| fizzbuzz n }
end

maxが先程map_uptoメソッドへ渡された値となります。
もとのコードで(1..100)となっている部分をmaxで置き換えた感じです。
1から順番に渡された引数までをnという値で順次fizzbuzzメソッドへ渡しています。
ここの戻り値がコンソール表示される値となります。

続いてこちら

fizz_buzz.rb
def fizzbuzz_hash
  { 'fizz' => 3, 'buzz' => 5 }.sort_by { |_, v| v }.to_h
end

こちらは単に固定値のHashを返すだけのメソッドとなります。
※ @QUANON さんにアドバイス頂き修正しました。Hashの中身の数値でsortすることで
中身の順番に依存しなくなります。

続いてこちら

fizz_buzz.rb
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を使うことで、文字列が空の場合は引数を、そうでない場合は文字列を返しています。

でもって最後

fizz_buzz.rb
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

いけてるようですね。
時間があればテストも追加しようと思います。

d-1hara
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away