Iteratorの調査
引き続きIteratorで色々実験。他の言語のスライスの真似事をさせてみました。便利そうなんですが、パフォーマンス的にはちょっと駄目かな。
#region Using directives using System; using System.Collections.Generic; using System.Text; #endregion namespace ConsoleApplication1 { using L = ListFunc<int>; public delegate bool Predicate<T>(T t); class ListFunc<T> { // begin以降の要素を列挙 public static IEnumerable<T> Range(IEnumerable<T> g, int begin) { if (begin < 0) throw new IndexOutOfRangeException(); IEnumerator<T> i = g.GetEnumerator(); while (begin > 0 && i.MoveNext()) --begin; if (begin != 0) throw new IndexOutOfRangeException(); while (i.MoveNext()) yield return i.Current; } // [begin, end)区間の要素を列挙 public static IEnumerable<T> Range(IEnumerable<T> g, int begin, int end) { if (begin < 0 || begin >= end) throw new IndexOutOfRangeException(); IEnumerator<T> i = g.GetEnumerator(); int n = begin; while (n > 0 && i.MoveNext()) --n; if (n != 0) throw new IndexOutOfRangeException(); n = end - begin; while (n-- > 0 && i.MoveNext()) yield return i.Current; } // predを満たす要素を列挙 public static IEnumerable<T> Find(IEnumerable<T> g, Predicate<T> pred) { foreach (T t in g) if (pred(t)) yield return t; } // IEnumerator<T>の大きさを求める public static int Len(IEnumerable<T> g) { int len = 0; IEnumerator<T> i = g.GetEnumerator(); while (i.MoveNext()) ++len; return len; } // 指定した位置の値を取得 public static T At(IEnumerable<T> g, int index) { foreach (T t in Range(g, index)) return t; throw new IndexOutOfRangeException(); } } class Program { // Iteratorを利用した簡易クイックソート static IEnumerable<int> Qsort(IEnumerable<int> g) { if (L.Len(g) == 0) yield break; // 先頭の要素をピボットとする(手抜き) int p = L.At(g, 0); // ピボットより小さい要素,ピボット,ピボットより大きい値のように並べる foreach (int n in Qsort(L.Find(L.Range(g, 1), delegate(int t) { return t < p; }))) yield return n; yield return p; foreach (int n in Qsort(L.Find(L.Range(g, 1), delegate(int t) { return t >= p; }))) yield return n; } // 乱数を取得する static IEnumerable<int> GetRand(int seed, int cnt) { Random r = new Random(seed); for (int i = 0; i < cnt; ++i ) yield return r.Next(99); } static void Main(string[] args) { // ソート前 foreach (int n in GetRand(7, 10)) Console.Write(n.ToString().PadLeft(4)); Console.WriteLine(); // ソート後 foreach (int n in Qsort(GetRand(7, 10))) Console.Write(n.ToString().PadLeft(4)); Console.ReadLine(); } } } /* 結果 37 86 65 5 36 66 4 94 83 84 4 5 36 37 65 66 83 84 86 94 */
ちょっとしたヘルパー関数をこさえてやると、スクリプト言語っぽいコードが書けます。スクリプト言語のスライスや、STLの<algorithm>、<functional>みたいなライブラリがあるとC#はもっと使いやすくなると思います。誰か作ってくれないかしら。(^^;