C# 3.0 LINQの続きです。

ラムダ式でも、{}で囲んで、複文(とC#でも言うのかな?)を形成できるようです。これを知らず、前回は匿名デリゲートを使っていました。

あと、null許容型を使うというアイデアを思い付いて、結果こうなりました。

var fizzbuzz = Enumerable.Range(1, 20).Select(
    i => {
        string s;
        if (i % 5 == 0)
            s = "fizz";
        else
            s = null;
        if (i % 3 == 0)
            s += "buzz";
        return s ?? i.ToString();
    });
foreach (var s in fizzbuzz)
{
    Console.WriteLine(s);
}

全く別のアプローチで、こんなのもどうでしょう。foreachが使えないのが痛いですけど。

var r = Enumerable.Range(1, 20);
var notFizzBuzz = from p in r select p % 3 != 0 && p % 5 != 0 ? p.ToString() : "";
var fizz = from p in r select p % 3 == 0 ? "Fizz" : "";
var buzz = from p in r select p % 5 == 0 ? "Buzz" : "";
 
using (var en = notFizzBuzz.GetEnumerator())
using (var ef = fizz.GetEnumerator())
using (var eb = buzz.GetEnumerator())
{
    while (en.MoveNext())
    {
        ef.MoveNext();
        eb.MoveNext();
        Console.Write(en.Current);
        Console.Write(ef.Current);
        Console.Write(eb.Current);
        Console.WriteLine();
    }
}

まだ試行錯誤は続きます。

Selectには要素数を2つ目の引数に取るラムダ式も受け付けるとのことで、こんなものも作ってみました。0から始まるのはご愛嬌。

var fizzbuzz = Enumerable.Repeat<object>(null, 21)
    .Select((o, i) => i % 15 == 0 ? "FizzBuzz" : null)
    .Select((s, i) => s ?? (i % 5 == 0 ? "Fizz" : null))
    .Select((s, i) => s ?? (i % 3 == 0 ? "Buzz" : null))
    .Select((s, i) => s ?? i.ToString());
var fizzbuzz = Enumerable.Repeat<object>(null, 21)
    .Select((s, i) => (i % 5 == 0 ? "Fizz" : null))
    .Select((s, i) => s + (i % 3 == 0 ? "Buzz" : null))
    .Select((s, i) => string.IsNullOrEmpty(s) ? i.ToString() : s);

下のコードで、string.IsNullOrEmpty(s) ? i.ToString() : sとしているのは、上の行で(string)null + (string)nullの結果が空文字列(長さ0の文字列)となるためです。詳しくは後日。最初はs ?? i.ToString()と書いていました。


暇ではないのに、暇潰しをさせてくれるとは、中々やってくれますね。LINQには、C++ STLのような世界の広さを感じます。

スポンサード リンク

この記事のカテゴリ

  • ⇒ 呪文FizzBuzz