読者です 読者をやめる 読者になる 読者になる

Line 1: Error: Invalid Blog('by Esehara' )

または私は如何にして心配するのを止めてバグを愛するようになったか

>> Zanmemo

あと何かあれは 「esehara あっと じーめーる」 か @esehara まで

新年初FizzBuzzで今年もめでたい!! RubyでEnumerableを利用したFizzBuzzを書く

初めに

プログラマには、新年が開けると、書き初めのようなものとして、FizzBuzzを書くという習慣があります。ごめんなさい、本当はそんな習慣無くて、自分が今でっち上げました。そこで、今回はRubyで、Enumerableを使ったFizzBuzzを書いてみようというのが、今回の趣旨となります。

FizzBuzzがわからない人は、あとで調べましょう。

なんでRubyでEnumerableなの?

もともとは、RacketというLisp処理系でFizzBuzzを書いたときに、「そういえば、Rubyでイテレーターみたいなものを実装するときってどういう風にすればいいんだっけ? yieldを使えば簡単に出来るっぽいんだけど、Rubyだし、Classでなんか実装できる方法があるっぽいんだよなー。ついでだし、eachとかmapとかも簡単に利用できるようにしたいなー」ということを思って、Stackoverflow日本語版で質問したところ、非常にわかりやすい解答が返ってきたので、「ありがてえ、ありがてえ」と思い、感謝の気持ちを示すために、よくわからない方向に向かって礼をして、おごそかな気持ちになりながら、実装したのが今回の経緯です。

ソースコード

class FizzBuzz
  def initialize i
    set! i
  end

  def to_i
    @i
  end

  def set! i
    @i = i
  end

  def to_s
    (fizzbuzz? && fizzbuzz) || @i.to_s
  end

  def fizzbuzz?
    !fizzbuzz.empty?
  end

  private
  def fizz
    "Fizz" if @i % 3 == 0
  end

  def buzz
    "Buzz" if @i % 5 == 0
  end

  def fizzbuzz
    "#{fizz}#{buzz}"
  end
end

class FizzBuzzIterator
  include Enumerable

  def initialize n
    @n = n
  end

  def each
    @n.each { |i| yield FizzBuzz.new i }
  end
end

ポイント

今回意識したポイントとしては、FizzBuzzのイテレーターを作成する部分と、実際のFizzBuzzを判定する部分を切り離したこと。これはLispのイテレーターっぽいFizzBuzzを実装したさいに、「そのFizzBuzzはなんの数字で出力されたものか」ということを意識させられた経緯による。

どういうことかというと、FizzBuzzでなんらかの文字が出力された時点で、ある程度情報は減ってしまう。数字が出力されているならまだしも、FizzBuzzのルールであるFizzBuzzFizzBuzzの文字列が出た時点で、その元の「数字」はなんだったのか、というのがわからなくなる。ある数列から、その数字が「Fizz, Buzz, FizzBuzzを出力するべきものなのか」というのはわかるのだが、逆にそれはもともとどの数列だったのか、というのがわからない。

従って、そのあたりの情報を縮減させないように、別途そのようなFizzBuzzの状態を管理するクラスを作成し、それを利用するという形にした。こうすることによって、例えば

puts FizzBuzzIterator.new(1..100).select{|f| f.fizzbuzz? }.map {|f| f.to_i }

といったように、Fizz, Buzz, FizzBuzzの文字列のどれかが表示される数字の一覧を取得するといったような使い方も可能になる。

この実装の問題

やりすぎるとFizzBuzzEnterprise Editionみたいになる可能性がある。今回は試し実装なのだけれど、勢い余って色々分離しすぎると、柔軟性がありそうで無いようなコードになる。

まとめ

というわけで、新年初FizzBuzzでした。皆さんも、新年なのでFizzBuzzを書いて、今年のプログラミングに対して、やっていく気持ちを育むのはどうでしょうか。