今更FizzBuzzをやってみる

今日初めて面接を担当することがあった。
で、色々聞いてみたのだけど、やっぱりFizzBuzzについて聞いてみたくなったので
次のような条件で15分ほど時間をとって、コードを書いてもらった。

3で割り切れる場合は 「Fizz」(Bizz Buzz の場合は 「Bizz」)、5で割り切れる場合は 「Buzz」、両者で割り切れる場合は 「Fizz Buzz」 (Bizz Buzz の場合は 「Bizz Buzz」)を数の代わりに発言しなければならない。

http://ja.wikipedia.org/wiki/Fizz_Buzz
  • 1から100以上で上の条件を満たすこと。
  • 利用する言語は何でもよい
  • 手元の紙に手書きでよい
  • 1から100までは、引数で渡してもいいし、ただのループでも良い


空いた時間が暇だったので、自分でも書いてみた

(1..100).each do |i| p i % 15 == 0 ? "FizzBuzz" : i % 3 == 0 ? "Fizz" : i % 5 == 0 ? "Buzz" : i end
(1..100).each do |i|
  p i % 15 == 0 ? "FizzBuzz"
                : i % 3 == 0 ? "Fizz" 
                             : i % 5 == 0 ? "Buzz"
                                          : i
end

普通の書き方。irbから実行するので、無理やり1行にしてみた。
三項演算子入れ子になっている所がパッと見、わかりにくい。


id:goking さんが面白い書き方をしていた。

  • "001”* n の文字列から [nil, nil, "Fizz", ...] の配列を作成
  • "00001" * m の文字列から[nil, nil, nil, nil, "Buzz", ...] の配列を作成
  • 両方の配列をArray#zipにより、2次元配列にまとめる
  • 両方に値がある場合は文字列を連結、片方に文字列がある場合はその文字列、お互いにnilならば数字を出力
  • n, m は適当な任意の数字

というふうに実現してた。

それを思い出しながら自分で再実装してみた。

([nil,nil,"Fizz"]*50).zip([nil,nil,nil,nil,"Buzz"]*50).each.with_index(1){|v,i|p v[0]&&v[1]?v[0]+v[1]:v[0]?v[0]:v[1]?v[1]:i}
([nil, nil, "Fizz"] * 50).zip([nil, nil, nil, nil, "Buzz"] * 50).each.with_index(1) {|v,i|
  p v[0] && v[1] ? v[0] + v[1]
                 : v[0] ? v[0]
                        : v[1] ? v[1]
                               : i
}

FizzとBuzzの配列はめんどくさいから直接作っている。

書いてみて思ったこと
配列で添字を取るときは、each_with_indexをいつも使っていたけど、each.with_indexとかけることに気がついた。
初期値を与えるなら、each.with_index(1)で1から連番で添字を取得できる。

今まで知らなかったAPIや書き方がわかったところが良かったな。