2005年C#の旅その5
今回はIteratorについて。Iteratorというとforeach専用みたいな感じで紹介されることが多いです。確かに、IEnumerator/IEnumerableを用意するのは面倒だったので大変便利ですが、Iteratorはプログラムの書き方変えてしまう可能性がある気がしています。単なるカンですけど。(^^;
Iteratorは何もC#の専売特許というわけでなく、他の言語でも既に用意されています。なので、使い方については他の言語の例から学べば良さそうです。ちょっとPythonからサンプルを引っ張ってきました。
#region Using directives using System; using System.Collections.Generic; using System.Text; #endregion namespace ConsoleApplication1 { delegate bool Predicate<T>(T value); /** * Python Cookbook 17.11 Wrapping an Unbounded Iterator to Restrict Its Output C#版 */ class Program { // conditionが真の間、gから値を取得する static IEnumerator<int> GenWhile(IEnumerator<int> g, Predicate<int> condition) { while (g.MoveNext()) { if (condition(g.Current)) yield return g.Current; else yield break; } } // n件数分gから取得する static IEnumerator<int> Take(int n, IEnumerator<int> g) { while (n-- > 0 && g.MoveNext()) { yield return g.Current; } } // n件飛ばしてgから取得する static IEnumerator<int> Drop(int n, IEnumerator<int> g) { while (n-- > 0 && g.MoveNext()) ; if (n > 0) yield break; while (g.MoveNext()) yield return g.Current; } // 偶数を生成 static IEnumerator<int> GenEven() { int n = 0; while (true) { n += 2; yield return n; } } static void Print(IEnumerator<int> g) { while (g.MoveNext()) Console.Write(g.Current.ToString().PadLeft(3)); Console.WriteLine(); } static void Main(string[] args) { // 偶数から12以下のものを取り出す Print(GenWhile(GenEven(), delegate(int n) { return n < 12; })); // 偶数から小さい順に5つ取り出す Print(Take(5, GenEven())); // 偶数から最初の5つを飛ばした、つぎの5つを取り出す Print(Take(5, Drop(5, GenEven()))); Console.ReadLine(); } } } /* 結果 2 4 6 8 10 2 4 6 8 10 12 14 16 18 20 */
配列を使わないプログラミングも面白いですね。