C#でFizzBuzzを実装する

FizzBuzzの問題を解くこと自体、やり尽くされた感がありますが、自分で書いたものを記事にしたことが無かった気がしたのでチャレンジしてみようと思います。

実装した環境はVS2017(15.7.2) + .NET4.7.2 (≒C#7.2)です。(C#6.0であれば問題ないので新しい環境でなくともほぼ大丈夫です。)

ルール確認と模範解答

まずルールと模範解答です。

ルールは有名なので簡単に、以下の通り。

  • 最初は1から自然数でインクリメント
  • 3の倍数で"Fizz"を出力
  • 5の倍数で"Buzz"を出力
  • 3と5の公倍数は"FizzBuzz"を出力

模範回答は、一番素直に書くとこんな感じかです。C#perじゃなくても読める感じです。

// 模範回答例
public static void Main(string[] args)
{
    for (int i = 1; i <= 100; i++)
    {
        if (i % 15 == 0)
        {
            Console.WriteLine("FizzBuzz");
        }
        else if (i % 5 == 0)
        {
            Console.WriteLine("Buzz");
        }
        else if (i % 3 == 0)
        {
            Console.WriteLine("Fizz");
        }
        else
        {
            Console.WriteLine(i);
        }
    }
}

少し短くFizzBuzz記述する

以下は自分のオリジナルです。

競技大会で出てくるようなヤバい黒魔術は唱えられないので、ほどほどなコードを書いてみたいと思います。

この世界だんだんと短くなるほど出力があってればOKの精神です。

一応ポイントの説明ですが以下の通りです。

  • 公倍数は計算しない。FizzとBuzzが連続で出ればFizzBuzz
  • Console.WriteLineを何回も書きたくないので先に出力を決定する
  • 文字が無ければ数字
public static void Main(string[] args)
{
    for (int i = 0; i++ < 100;)
    {
        string str = (i % 3 == 0 ? "Fizz" : "") + (i % 5 == 0 ? "Buzz" : "");
        Console.WriteLine(str == "" ? $"{i}" : str);
    }
}
// [出力]
// 1
// 2
// Fizz
// 4
// Buzz
// Fizz
// 7
// 8

また、おしゃれ感を出すためにfor文を拡張メソッドに変えると全体の雰囲気が明るくなります(謎

おしゃれ感を優先(投げやり)のあまり前述のより長いですし、計算量は通常の倍です(;^ω^)

public static void Main(string[] args)
{
    // お洒落感のあるコード
    string f (int i ) { return (i % 3 == 0 ? "Fizz" : "") + (i % 5 == 0 ? "Buzz" : ""); }
    Enumerable.Range(1, 100).ToList().ForEach(i => Console.WriteLine(f(i) == "" ? $"{i}" : f(i)));
    
    // fはデリゲートでもOK
    //Func<int, string> f = i => (i % 3 == 0 ? "Fizz" : "") + (i % 5 == 0 ? "Buzz" : "");
}

ちなみにforの代わりにForEachを通常の式で使うのNGです。パフォーマンスが悪いです。4割くらい遅いです。リストの中を一括で変換する処理を書く時にラムダ的可読性以外のメリットが無いのでfor か foreachで記述しています。

最新の企画を使ってFizzBuzz

最後のお洒落感を流用してC#7.3のタプル同士の比較という最新規格を使ってFizzBuzzしてみようと思います。

タプルの中身が空だったら数字を出しています。

以下のコードコンパイルするには、プロジェクトからC#7.3の有効化とNuGetからValueTypleを参照に追加します。

// C#7.0のローカル関数、C#7.3のタプルの比較を使ったコード
(object, object) f(int n) => (n % 3 == 0 ? "Fizz" : "", n % 5 == 0 ? "Buzz" : "");
for (int i = 0; i++ < 100;)
{
    Console.WriteLine(f(i) == ("", "") ? $"{i}" : $"{f(i)}".Replace(", ", "").Trim('(', ')'));
}

以上です。