LINQ to Object のイディオム その3 : シーケンス生成

「標準クエリ演算子は、"シーケンス" を操作します。ある型 T に対してインターフェイス IEnumerable を実装するオブジェクトはすべて、その型のシーケンスと見なされます。」.NET 標準クエリ演算子より引用。
シーケンスの「生成演算子」あたりがお題。
冒頭の資料で挙げられてる生成演算子は、Range, Repeat, Empty の3つ。これだけだと記事にするまでもないので、ネタコードで遊んでるうちに気づいた手軽な生成方法を改めて書いときます(これ→id:siokoshou:20071129)。
シーケンスとは IEnumerable なので、最も手軽な生成方法は配列やコレクションを作ってしまうこと。IEnumerable はデータ構造も手続きも同じように扱えてしまう器用さがいいですね。「技術的には簡単だけど、その効果は深遠なもの」ってやつ*1
おもしろいことに文字列も文字のシーケンスです。一文字一文字について何かするなら LINQ が使えます。

using System;
using System.Linq;

class Program
{
  static void Main()
  {
    var seq1 = new[] { 1, 2, 3 }.Concat( new[] { 2007 } );
    var seq2 = Enumerable.Repeat( 10, 2 ); // 10, 10
    var seq3 = Enumerable.Range( 20, 3 ); // 20, 21, 22
    var seq4 = Enumerable.Empty<int>();
    var seq = seq1.Concat( seq2 ).Concat( seq3 ).Concat( seq4 );

    seq.ToList().ForEach( Console.WriteLine );
    Console.WriteLine();

    // siokoshou の中に aiueo は何回出てくるか?
    var q= "siokoshou".Join( "aiueo", c => c, c => c, ( c, d ) => c ).Count();
    Console.WriteLine( q);

    // シーケンスの比較
    Console.WriteLine(
      Enumerable.Range( 1, 2 ).SequenceEqual( Enumerable.Empty<int>() ) );

    Console.ReadKey();
  }
}

シーケンスの比較って、ものっすごい抽象度が高い操作ですねぇ。MoveNext() とか細かい動作から、よくもまあこの高みにまで達したなあと。

*1:この言葉は McIlroy 神が Unix のパイプ&フィルタについて語った言葉。The Art of UNIX Programming より引用。McIlroy さんはパイプ&フィルタの生みの親。