using System; using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; using System.Linq; using System.Text; namespace Umbraco.Core { /// /// Extensions for enumerable sources /// public static class EnumerableExtensions { public static IEnumerable> InGroupsOf(this IEnumerable source, int groupSize) { if (source == null) throw new NullReferenceException("source"); // enumerate the source only once! return new InGroupsEnumerator(source, groupSize).Groups(); } // this class makes sure that the source is enumerated only ONCE // which means that when it is enumerated, the actual groups content // has to be evaluated at the same time, and stored in an array. private class InGroupsEnumerator { private readonly IEnumerator _source; private readonly int _count; private bool _mightHaveNext; public InGroupsEnumerator(IEnumerable source, int count) { _source = source.GetEnumerator(); _count = count; _mightHaveNext = true; } public IEnumerable> Groups() { while (_mightHaveNext && _source.MoveNext()) yield return Group().ToArray(); // see note above } private IEnumerable Group() { var c = 0; do { yield return _source.Current; } while (++c < _count && _source.MoveNext()); _mightHaveNext = c == _count; } } /// The distinct by. /// The source. /// The key selector. /// Source type /// Key type /// the unique list public static IEnumerable DistinctBy(this IEnumerable source, Func keySelector) where TKey : IEquatable { return source.Distinct(DelegateEqualityComparer.CompareMember(keySelector)); } /// /// Returns a sequence of length whose elements are the result of invoking . /// /// /// The factory. /// The count. /// public static IEnumerable Range(Func factory, int count) { for (int i = 1; i <= count; i++) { yield return factory.Invoke(i - 1); } } /// The if not null. /// The items. /// The action. /// The type public static void IfNotNull(this IEnumerable items, Action action) where TItem : class { if (items != null) { foreach (TItem item in items) { item.IfNotNull(action); } } } /// The for each. /// The items. /// The func. /// item type /// Result type /// the Results public static TResult[] ForEach(this IEnumerable items, Func func) { return items.Select(func).ToArray(); } /// The for each. /// The items. /// The action. /// Item type /// list of TItem public static IEnumerable ForEach(this IEnumerable items, Action action) { if (items != null) { foreach (TItem item in items) { action(item); } } return items; } /// The flatten list. /// The items. /// The select child. /// Item type /// list of TItem [SuppressMessage("Microsoft.Design", "CA1006:DoNotNestGenericTypesInMemberSignatures", Justification = "By design")] public static IEnumerable FlattenList(this IEnumerable items, Func> selectChild) { IEnumerable children = items != null && items.Any() ? items.SelectMany(selectChild).FlattenList(selectChild) : Enumerable.Empty(); if (items != null) { return items.Concat(children); } return null; } /// /// Returns true if all items in the other collection exist in this collection /// /// /// /// /// public static bool ContainsAll(this IEnumerable source, IEnumerable other) { var matches = true; foreach (var i in other) { matches = source.Contains(i); if (!matches) break; } return matches; } /// /// Returns true if the source contains any of the items in the other list /// /// /// /// /// public static bool ContainsAny(this IEnumerable source, IEnumerable other) { return other.Any(i => source.Contains(i)); } /// /// Removes all matching items from an . /// /// /// The list. /// The predicate. /// public static void RemoveAll(this IList list, Func predicate) { for (var i = 0; i < list.Count; i++) { if (predicate(list[i])) { list.RemoveAt(i--); } } } /// /// Removes all matching items from an . /// /// /// The list. /// The predicate. /// public static void RemoveAll(this ICollection list, Func predicate) { var matches = list.Where(predicate).ToArray(); foreach (var match in matches) { list.Remove(match); } } public static IEnumerable SelectRecursive( this IEnumerable source, Func> recursiveSelector, int maxRecusionDepth = 100) { var stack = new Stack>(); stack.Push(source.GetEnumerator()); try { while (stack.Count > 0) { if (stack.Count > maxRecusionDepth) throw new InvalidOperationException("Maximum recursion depth reached of " + maxRecusionDepth); if (stack.Peek().MoveNext()) { var current = stack.Peek().Current; yield return current; stack.Push(recursiveSelector(current).GetEnumerator()); } else { stack.Pop().Dispose(); } } } finally { while (stack.Count > 0) { stack.Pop().Dispose(); } } } /// /// Filters a sequence of values to ignore those which are null. /// /// /// The coll. /// /// public static IEnumerable WhereNotNull(this IEnumerable coll) where T : class { return coll.Where(x => x != null); } public static IEnumerable ForAllThatAre(this IEnumerable sequence, Action projection) where TActual : class { return sequence.Select( x => { if (typeof(TActual).IsAssignableFrom(x.GetType())) { var casted = x as TActual; projection.Invoke(casted); } return x; }); } /// /// Finds the index of the first item matching an expression in an enumerable. /// /// The type of the enumerated objects. /// The enumerable to search. /// The expression to test the items against. /// The index of the first matching item, or -1. public static int FindIndex(this IEnumerable items, Func predicate) { return FindIndex(items, 0, predicate); } /// /// Finds the index of the first item matching an expression in an enumerable. /// /// The type of the enumerated objects. /// The enumerable to search. /// The index to start at. /// The expression to test the items against. /// The index of the first matching item, or -1. public static int FindIndex(this IEnumerable items, int startIndex, Func predicate) { if (items == null) throw new ArgumentNullException("items"); if (predicate == null) throw new ArgumentNullException("predicate"); if (startIndex < 0) throw new ArgumentOutOfRangeException("startIndex"); var index = startIndex; if (index > 0) items = items.Skip(index); foreach (var item in items) { if (predicate(item)) return index; index++; } return -1; } ///Finds the index of the first occurence of an item in an enumerable. ///The enumerable to search. ///The item to find. ///The index of the first matching item, or -1 if the item was not found. public static int IndexOf(this IEnumerable items, T item) { return items.FindIndex(i => EqualityComparer.Default.Equals(item, i)); } } }