だるろぐ

明日できることは、今日しない。

WebMatrix で FizzBuzz

Nomi Licking the Canon cat

それで、そういった類の開発者を見分けるための質問を作り始め、私が「Fizz-Buzz問題」と呼んでいる問題のクラスを考え出した。これはイギリスの学校の子供たちがよくやっている遊び(というかやらされている遊び)にちなんで名付けた。Fizz-Buzz問題の例はこんな感じだ。

1から100までの数をプリントするプログラムを書け。ただし3の倍数のときは数の代わりに「Fizz」と、5の倍数のときは「Buzz」とプリントし、3と5両方の倍数の場合には「FizzBuzz」とプリントすること。

ちゃんとしたプログラマであれば、これを実行するプログラムを2分とかからずに紙に書き出せるはずだ。怖い事実を聞きたい? コンピュータサイエンス学科卒業生の過半数にはそれができないのだ。自称上級プログラマが答えを書くのに10-15分もかかっているのを見たこともある。

どうしてプログラマに・・・プログラムが書けないのか?

手元にWebMatrixがあったので、試しに FizzBuzz をプリントアウトするコードを書いてみた。

本能のおもむくままに

    # /App_Code/FizzBuzz.cshtml
    
    @helper Print(int count = 100)
    {
        foreach (var i in Enumerable.Range(1, count))
        {
            var s = string.Empty;

            if (i % 3 == 0) { s += "Fizz"; }
            if (i % 5 == 0) { s += "Buzz"; }
            if (s == string.Empty) { s += i.ToString(); }

            <p>@s</p>
        }
    }

何も考えずに、自分なりの素直なコード。@FizzBuzz.Print() で期待通りに出力される。

自己採点 & 反省

そのあと、いろいろぐぐってみた。普通はだいたいこのように書くみたいだ。

    @helper Print2(int count = 100)
    {
        for (int i = 1; i <= count; i++)
        {
            var fizz = (i % 3 == 0);
            var buzz = (i % 5 == 0);
        
            if (fizz && !buzz) {
                <p>Fizz</p>
            } else if (!fizz && buzz) {
                <p>Buzz</p>
            } else if (fizz && buzz) {
                <p>FizzBuzz</p>
            } else {
                <p>@i</p>
            }
        }
    }

1. for のほうが速い。けれど、Enumerable.Range のほうが個人的には読みやすい。

2. s == string.Empty に「3の倍数でも5の倍数でもない」という意味をもたせるより、ちゃんと条件分岐として記述する方がわかりやすい。速度的にもおそらく優れる。

3. どうせならLINQで書くべきだよね。

ほかにもなにかあったら教えて下さい。