using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Linq; using System.Text; namespace BuzzGUI.Common { public static class LinqExtensions { public static IEnumerable Traverse(this IEnumerable source, Func> fnRecurse) { foreach (T item in source) { yield return item; IEnumerable seqRecurse = fnRecurse(item); if (seqRecurse != null) { foreach (T itemRecurse in Traverse(seqRecurse, fnRecurse)) yield return itemRecurse; } } } public static void Remove(this IDictionary d, Func p) { foreach (var k in d.Keys.Where(k => p(k)).ToArray()) d.Remove(k); } public static ReadOnlyCollection ToReadOnlyCollection(this IEnumerable source) { return source.ToList().AsReadOnly(); } public static IEnumerable SelectTwo(this IEnumerable source, Func firstselector, Func secondselector) { using (var i = source.GetEnumerator()) { while (i.MoveNext()) { yield return firstselector(i.Current); yield return secondselector(i.Current); } } } public static IEnumerable SelectFromTwo(this IEnumerable source, Func selector) { using (var i = source.GetEnumerator()) { while (i.MoveNext()) { var first = i.Current; if (!i.MoveNext()) break; yield return selector(first, i.Current); } } } public static int FindIndex(this IEnumerable source, Func condition) { int index = 0; foreach (var e in source) { if (condition(e)) break; index++; } return index; } public static int FindIndex(this IEnumerable source, TState seed, Func select, Func condition) where TState : struct { int index = 0; TState state = seed; foreach (var e in source) { state = select(state, e); if (condition(state)) break; index++; } return index; } public static void FindAndExecute(this IEnumerable source, TState seed, Func select, Func condition, Action action) where TState : struct { TState state = seed; foreach (var e in source) { state = select(state, e); if (condition(state)) { action(e); break; } } } public static HashSet ToHashSet(this IEnumerable source) { return new HashSet(source); } // like SingleOrDefault but also returns default when there's more than one element instead of throwing public static T OnlyOrDefault(this IEnumerable source) { if (source == null) throw new ArgumentNullException("source"); IList list = source as IList; if (list != null) { switch (list.Count) { case 0: return default(T); case 1: return list[0]; } } else { using (IEnumerator e = source.GetEnumerator()) { if (!e.MoveNext()) return default(T); T result = e.Current; if (!e.MoveNext()) return result; } } return default(T); } public static IEnumerable Shuffle(this IEnumerable source) { return source.Shuffle(new Random()); } public static IEnumerable Shuffle(this IEnumerable source, Random rng) { if (source == null) throw new ArgumentNullException("source"); if (rng == null) throw new ArgumentNullException("rng"); return source.ShuffleIterator(rng); } private static IEnumerable ShuffleIterator(this IEnumerable source, Random rng) { List buffer = source.ToList(); for (int i = 0; i < buffer.Count; i++) { int j = rng.Next(i, buffer.Count); yield return buffer[j]; buffer[j] = buffer[i]; } } public static IEnumerable Return(T value) { yield return value; } public static IEnumerable Do(this IEnumerable source, Action action) { foreach (var i in source) { action(i); yield return i; } } public static IEnumerable Do(this IEnumerable source, Action action) { int index = 0; foreach (var i in source) { action(i, index++); yield return i; } } public static void Run(this IEnumerable source) { foreach (var i in source) ; } public static void Run(this IEnumerable source, Action action) { foreach (var i in source) action(i); } public static void Run(this IEnumerable source, Action action) { int index = 0; foreach (var i in source) action(i, index++); } public static void Run(this IEnumerable source, Action action) where U: T { foreach (var i in source) { if (i is U) action((U)i); } } public static IEnumerable RangeExcludingEnd(int start, int end, int step) { for (int i = start; i < end; i += step) yield return i; } public static IEnumerable RangeIncludingEnd(int start, int end, int step) { for (int i = start; i <= end; i += step) yield return i; } public static IEnumerable RangeExcludingEnd(double start, double end, double step) { if (step == 0) throw new ArgumentException("step"); int n = (int)Math.Ceiling((end - start) / step); for (int i = 0; i < n; i++) yield return start + i * step; } public static IEnumerable RangeIncludingEnd(double start, double end, double step) { return RangeExcludingEnd(start, end, step).Concat(Return(end)); } // ignores empty lists public static IEnumerable> Split(this IEnumerable source, T delimiter) { var list = new List(); foreach (var i in source) { if ((i == null && delimiter == null) || (i != null && i.Equals(delimiter))) { if (list.Count > 0) { yield return list; list.Clear(); } } else { list.Add(i); } } if (list.Count > 0) yield return list; } public static int IndexOfMinBy(this IEnumerable source, Func selector) { int index = 0; TKey min = default(TKey); bool first = true; int minIndex = 0; foreach (var e in source) { var k = selector(e); if (first || Comparer.Default.Compare(k, min) < 0) { min = k; minIndex = index; first = false; } index++; } return minIndex; } } }