時代遅れひとりFizzBuzz祭り Ruby編

時代遅れひとりFizzBuzz祭り、今回はRuby。前回がPerlだったので、Perlの影響も大きく受けているRubyにしてみた。

Rubyはテキスト処理系統のツールを自作する時によく使う。以前はgawkを使っていたけど、やはりgawkは独特な所があって、本格的なツールを作るにはちょっと向いていないというか、正直今ではgawkよりも便利な言語がある訳で、色々と物色したのだ。

その際、何故かPerlを飛び越して一気にRubyに進んでしまった。多分、本家本元のリファレンスをWeb上で日本語で読めたからだと思う。

RubyFizzBuzzを書くとすると、こんな感じ。基本的に手続き型の発想の延長で使っているので、Rubyっぽくないコードかもしれない。ちなみにRuby 1.8.7だ。

#!/usr/bin/ruby

def fizzbuzz(n)
  fb = []

  fb.push('Fizz') if n % 3 == 0
  fb.push('Buzz') if n % 5 == 0

  if fb.empty?
    n.to_s
  else
    fb.join
  end
end

(1..100).each {|n| puts fizzbuzz(n) }

書いてから気づいたが、メソッドの中身が何か変だ。多分、直前までJScriptのコードを書いていた為だろう。

ところでRubyでは、配列を生成する時に任意のブロックを評価した結果を値として設定することが可能らしい。ということで別解としてこんなコードを書いてみた。

#!/usr/bin/ruby

Array.new(100) {|i| i+1 }.map {|i|
  s = ''
  s = 'Fizz' if i % 3 == 0
  s += 'Buzz' if i % 5 == 0
  s = i if s == ''
  s
}.each {|i| puts i }

1〜100までの値が格納された配列を生成し、その値をFizzBuzz用に変換した新しい配列を生成し、その要素を表示している。

しかしよく考えると、配列を2回生成しているのは、何というか自分の中のRuby伝説的にNGな気がする。自分のイメージでは、ちょっとRuby的ではない。

だからという訳ではないが、最初からFizzBuzz用の値の配列を生成するように1工程削ってみた。

#!/usr/bin/ruby

Array.new(100) {|i|
  s = ''
  s = 'Fizz' if i % 3 == 2
  s += 'Buzz' if i % 5 == 4
  s = i+1 if s == ''
  s
}.each {|i| puts i }

更に、値を変換する部分をメソッドとして切り出してみた。

#!/usr/bin/ruby

def fizzbuzz(n)
  val = (n % 3 == 0) ? 'Fizz' : ''
  val << 'Buzz' if n % 5 == 0
  val = n if val == ''
  val
end

Array.new(100) {|i| fizzbuzz(i+1) }.each {|i| puts i }

これが最終形。

しかし、ここまで書いておいてアレだが、最後の1行が微妙に長ったらしいのが気に入らない。むしろ、こちらの方がスッキリする。

#!/usr/bin/ruby

def fizzbuzz(n)
  val = (n % 3 == 0) ? 'Fizz' : ''
  val << 'Buzz' if n % 5 == 0
  val == '' ? n : val
end

(1..100).each {|n| puts fizzbuzz(n) }

結局、最初のコードに戻ってきてしまった。違うのはメソッドfizzbuzzの中身だけだ。