X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mcs%2Fclass%2FSystem.Core%2FSystem.Linq%2FEnumerable.cs;h=d2c98d0a1954f16a877a18c2c856d759747d2563;hb=cc2c56a916645e45991c43f86409966218a6a177;hp=96e69e57424ec3075c8fb413f867e0d5f5f597e0;hpb=11e8c41da5245c5f42cdd5e94c808d650e6fc81a;p=mono.git diff --git a/mcs/class/System.Core/System.Linq/Enumerable.cs b/mcs/class/System.Core/System.Linq/Enumerable.cs index 96e69e57424..d2c98d0a195 100644 --- a/mcs/class/System.Core/System.Linq/Enumerable.cs +++ b/mcs/class/System.Core/System.Linq/Enumerable.cs @@ -1,2850 +1,2349 @@ -// Permission is hereby granted, free of charge, to any person obtaining -// a copy of this software and associated documentation files (the -// "Software"), to deal in the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, -// distribute, sublicense, and/or sell copies of the Software, and to -// permit persons to whom the Software is furnished to do so, subject to -// the following conditions: -// -// The above copyright notice and this permission notice shall be -// included in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -// -// Authors: -// Marek Safar (marek.safar@gmail.com) -// Antonello Provenzano -// Alejandro Serrano "Serras" (trupill@yahoo.es) -// - -using System; -using System.Collections; -using System.Collections.Generic; -using System.Collections.ObjectModel; - -namespace System.Linq -{ - public static class Enumerable - { - #region Aggregate - public static TSource Aggregate(this IEnumerable source, Func func) - { - if (source == null || func == null) - throw new ArgumentNullException(); - - int counter = 0; - TSource folded = default(TSource); - - foreach (TSource element in source) - { - if (counter == 0) - folded = element; - else - folded = func(folded, element); - } - - if (counter == 0) - throw new InvalidOperationException(); - else - return folded; - } - - - public static TAccumulate Aggregate(this IEnumerable source, - TAccumulate seed, Func func) - { - if (source == null || func == null) - throw new ArgumentNullException(); - - TAccumulate folded = seed; - foreach (TSource element in source) - folded = func(folded, element); - return folded; - } - - - public static TResult Aggregate(this IEnumerable source, TAccumulate seed, Func func, Func resultSelector) - { - if (source == null) - throw new ArgumentNullException("source"); - if (func == null) - throw new ArgumentNullException("func"); - if (resultSelector == null) - throw new ArgumentNullException("resultSelector"); - - TAccumulate result = seed; - foreach (TSource e in source) - result = func(result, e); - return resultSelector(result); - } - #endregion - - #region All - public static bool All(this IEnumerable source, Func predicate) - { - if (source == null || predicate == null) - throw new ArgumentNullException(); - - foreach (TSource element in source) - if (!predicate(element)) - return false; - return true; - } - #endregion - - #region Any - public static bool Any(this IEnumerable source) - { - if (source == null) - throw new ArgumentNullException(); - - foreach (TSource element in source) - return true; - return false; - } - - - public static bool Any(this IEnumerable source, Func predicate) - { - if (source == null || predicate == null) - throw new ArgumentNullException(); - - foreach (TSource element in source) - if (predicate(element)) - return true; - return false; - } - #endregion - - #region AsEnumerable - public static IEnumerable AsEnumerable(this IEnumerable source) - { - return source; - } - #endregion - - #region Average - public static double Average(this IEnumerable source) - { - if (source == null) - throw new ArgumentNullException(); - - long sum = 0; - long counter = 0; - foreach (int element in source) - { - sum += element; - counter++; - } - - if (counter == 0) - throw new InvalidOperationException(); - else - return (double)sum / (double)counter; - } - - - public static double? Average(this IEnumerable source) - { - if (source == null) - throw new ArgumentNullException(); - - bool onlyNull = true; - long sum = 0; - long counter = 0; - foreach (int? element in source) - { - if (element.HasValue) - { - onlyNull = false; - sum += element.Value; - counter++; - } - } - return (onlyNull ? null : (double?)sum / (double?)counter); - } - - - public static double Average(this IEnumerable source) - { - if (source == null) - throw new ArgumentNullException(); - - long sum = 0; - long counter = 0; - foreach (long element in source) - { - sum += element; - counter++; - } - - if (counter == 0) - throw new InvalidOperationException(); - else - return (double)sum / (double)counter; - } - - - public static double? Average(this IEnumerable source) - { - if (source == null) - throw new ArgumentNullException(); - - bool onlyNull = true; - long sum = 0; - long counter = 0; - foreach (long? element in source) - { - if (element.HasValue) - { - onlyNull = false; - sum += element.Value; - counter++; - } - } - return (onlyNull ? null : (double?)sum / (double?)counter); - } - - - public static double Average(this IEnumerable source) - { - if (source == null) - throw new ArgumentNullException(); - - double sum = 0; - double counter = 0; - foreach (double element in source) - { - sum += element; - counter++; - } - - if (counter == 0) - throw new InvalidOperationException(); - else - return sum / counter; - } - - - public static double? Average(this IEnumerable source) - { - if (source == null) - throw new ArgumentNullException(); - - bool onlyNull = true; - double sum = 0; - double counter = 0; - foreach (double? element in source) - { - if (element.HasValue) - { - onlyNull = false; - sum += element.Value; - counter++; - } - } - return (onlyNull ? null : (double?)(sum / counter)); - } - - - public static decimal Average(this IEnumerable source) - { - if (source == null) - throw new ArgumentNullException(); - - decimal sum = 0; - decimal counter = 0; - foreach (decimal element in source) - { - sum += element; - counter++; - } - - if (counter == 0) - throw new InvalidOperationException(); - else - return sum / counter; - } - - - public static decimal? Average(this IEnumerable source) - { - if (source == null) - throw new ArgumentNullException(); - - bool onlyNull = true; - decimal sum = 0; - decimal counter = 0; - foreach (decimal? element in source) - { - if (element.HasValue) - { - onlyNull = false; - sum += element.Value; - counter++; - } - } - return (onlyNull ? null : (decimal?)(sum / counter)); - } - - - public static double Average(this IEnumerable source, Func selector) - { - if (source == null || selector == null) - throw new ArgumentNullException(); - - long sum = 0; - long counter = 0; - foreach (TSource item in source) - { - sum += selector(item); - counter++; - } - - if (counter == 0) - throw new InvalidOperationException(); - else - return (double)sum / (double)counter; - } - - - public static double? Average(this IEnumerable source, Func selector) - { - if (source == null || selector == null) - throw new ArgumentNullException(); - - bool onlyNull = true; - long sum = 0; - long counter = 0; - foreach (TSource item in source) - { - int? element = selector(item); - if (element.HasValue) - { - onlyNull = false; - sum += element.Value; - counter++; - } - } - return (onlyNull ? null : (double?)sum / (double?)counter); - } - - - public static double Average(this IEnumerable source, Func selector) - { - if (source == null || selector == null) - throw new ArgumentNullException(); - - long sum = 0; - long counter = 0; - foreach (TSource item in source) - { - sum += selector(item); - counter++; - } - - if (counter == 0) - throw new InvalidOperationException(); - else - return (double)sum / (double)counter; - } - - - public static double? Average(this IEnumerable source, Func selector) - { - if (source == null || selector == null) - throw new ArgumentNullException(); - - bool onlyNull = true; - long sum = 0; - long counter = 0; - foreach (TSource item in source) - { - long? element = selector(item); - if (element.HasValue) - { - onlyNull = false; - sum += element.Value; - counter++; - } - } - return (onlyNull ? null : (double?)sum / (double?)counter); - } - - - public static double Average(this IEnumerable source, Func selector) - { - if (source == null || selector == null) - throw new ArgumentNullException(); - - double sum = 0; - double counter = 0; - foreach (TSource item in source) - { - sum += selector(item); - counter++; - } - - if (counter == 0) - throw new InvalidOperationException(); - else - return sum / counter; - } - - - public static double? Average(this IEnumerable source, Func selector) - { - if (source == null || selector == null) - throw new ArgumentNullException(); - - bool onlyNull = true; - double sum = 0; - double counter = 0; - foreach (TSource item in source) - { - double? element = selector(item); - if (element.HasValue) - { - onlyNull = false; - sum += element.Value; - counter++; - } - } - return (onlyNull ? null : (double?)(sum / counter)); - } - - - public static decimal Average(this IEnumerable source, Func selector) - { - if (source == null || selector == null) - throw new ArgumentNullException(); - - decimal sum = 0; - decimal counter = 0; - foreach (TSource item in source) - { - sum += selector(item); - counter++; - } - - if (counter == 0) - throw new InvalidOperationException(); - else - return sum / counter; - } - - - public static decimal? Average(this IEnumerable source, Func selector) - { - if (source == null || selector == null) - throw new ArgumentNullException(); - - bool onlyNull = true; - decimal sum = 0; - decimal counter = 0; - foreach (TSource item in source) - { - decimal? element = selector(item); - if (element.HasValue) - { - onlyNull = false; - sum += element.Value; - counter++; - } - } - return (onlyNull ? null : (decimal?)(sum / counter)); - } - #endregion - - #region Cast - public static IEnumerable Cast(this IEnumerable source) - { - if (source == null) - throw new ArgumentNullException(); - - foreach (object element in source) - yield return (TSource)element; - } - #endregion - - #region Concat - public static IEnumerable Concat(this IEnumerable first, IEnumerable second) - { - if (first == null || second == null) - throw new ArgumentNullException(); - - foreach (TSource element in first) - yield return element; - foreach (TSource element in second) - yield return element; - } - - #endregion - - #region Contains - - public static bool Contains(this IEnumerable source, TSource value) - { - if (source is ICollection) - { - ICollection collection = (ICollection)source; - return collection.Contains(value); - } - - return Contains(source, value, null); - } - - - public static bool Contains(this IEnumerable source, TSource value, IEqualityComparer comparer) - { - if (source == null) - throw new ArgumentNullException("source"); - - if (comparer == null) - comparer = EqualityComparer.Default; - - - foreach (TSource e in source) - { - if (comparer.Equals(e, value)) - return true; - } - - return false; - } - #endregion - - #region Count - public static int Count(this IEnumerable source) - { - if (source == null) - throw new ArgumentNullException(); - - if (source is ICollection) - return ((ICollection)source).Count; - else - { - int counter = 0; - foreach (TSource element in source) - counter++; - return counter; - } - } - - - public static int Count(this IEnumerable source, Func selector) - { - if (source == null || selector == null) - throw new ArgumentNullException(); - - int counter = 0; - foreach (TSource element in source) - if (selector(element)) - counter++; - - return counter; - } - #endregion - - #region DefaultIfEmpty - - public static IEnumerable DefaultIfEmpty(this IEnumerable source) - { - if (source == null) - throw new ArgumentNullException(); - - bool noYield = true; - foreach (TSource item in source) - { - noYield = false; - yield return item; - } - - if (noYield) - yield return default(TSource); - } - - - public static IEnumerable DefaultIfEmpty(this IEnumerable source, TSource defaultValue) - { - if (source == null) - throw new ArgumentNullException(); - - bool noYield = true; - foreach (TSource item in source) - { - noYield = false; - yield return item; - } - - if (noYield) - yield return defaultValue; - } - - #endregion - - #region Distinct - - public static IEnumerable Distinct(this IEnumerable source) - { - return Distinct(source, null); - } - - public static IEnumerable Distinct(this IEnumerable source, IEqualityComparer comparer) - { - if (source == null) - throw new ArgumentNullException(); - - if (comparer == null) - comparer = EqualityComparer.Default; - - List items = new List(); - foreach (TSource element in source) - { - if (!Contains (items, element, comparer)) - { - items.Add(element); - yield return element; - } - } - } - #endregion - - #region ElementAt - - public static TSource ElementAt(this IEnumerable source, int index) - { - if (source == null) - throw new ArgumentNullException(); - if (index < 0) - throw new ArgumentOutOfRangeException(); - - if (source is IList) - return ((IList)source)[index]; - else - { - int counter = 0; - foreach (TSource element in source) - { - if (counter == index) - return element; - counter++; - } - throw new ArgumentOutOfRangeException(); - } - } - - #endregion - - #region ElementAtOrDefault - - public static TSource ElementAtOrDefault(this IEnumerable source, int index) - { - if (source == null) - throw new ArgumentNullException(); - if (index < 0) - return default(TSource); - - if (source is IList) - { - if (((IList)source).Count >= index) - return default(TSource); - else - return ((IList)source)[index]; - } - else - { - int counter = 0; - foreach (TSource element in source) - { - if (counter == index) - return element; - counter++; - } - return default(TSource); - } - } - - #endregion - - #region Empty - public static IEnumerable Empty() - { - return new List(); - } - #endregion - - #region Except - - public static IEnumerable Except(this IEnumerable first, IEnumerable second) - { - return Except(first, second, null); - } - - public static IEnumerable Except(this IEnumerable first, IEnumerable second, IEqualityComparer comparer) - { - if (first == null || second == null) - throw new ArgumentNullException(); - - if (comparer == null) - comparer = EqualityComparer.Default; - - List items = new List(Distinct(first)); - foreach (TSource element in second) - { - int index = IndexOf(items, element, comparer); - if (index == -1) - items.Add(element); - else - items.RemoveAt(index); - } - foreach (TSource item in items) - yield return item; - } - - #endregion - - #region First - - public static TSource First(this IEnumerable source) - { - if (source == null) - throw new ArgumentNullException(); - - foreach (TSource element in source) - return element; - - throw new InvalidOperationException(); - } - - - public static TSource First(this IEnumerable source, Func predicate) - { - if (source == null || predicate == null) - throw new ArgumentNullException(); - - foreach (TSource element in source) - { - if (predicate(element)) - return element; - } - - throw new InvalidOperationException(); - } - - #endregion - - #region FirstOrDefault - - public static T FirstOrDefault(this IEnumerable source) - { - if (source == null) - throw new ArgumentNullException(); - - foreach (T element in source) - return element; - - return default(T); - } - - - public static T FirstOrDefault(this IEnumerable source, Func predicate) - { - if (source == null || predicate == null) - throw new ArgumentNullException(); - - foreach (T element in source) - { - if (predicate(element)) - return element; - } - - return default(T); - } - - #endregion - - #region GroupBy - - private static List ContainsGroup( - Dictionary> items, K key, IEqualityComparer comparer) - { - IEqualityComparer comparerInUse = (comparer ?? EqualityComparer.Default); - foreach (KeyValuePair> value in items) - { - if (comparerInUse.Equals(value.Key, key)) - return value.Value; - } - return null; - } - - - public static IEnumerable> GroupBy(this IEnumerable source, - Func keySelector) - { - return GroupBy(source, keySelector, null); - } - - - public static IEnumerable> GroupBy(this IEnumerable source, - Func keySelector, IEqualityComparer comparer) - { - if (source == null || keySelector == null) - throw new ArgumentNullException(); - - Dictionary> groups = new Dictionary>(); - List nullList = new List(); - int counter = 0; - int nullCounter = -1; - - foreach (TSource element in source) - { - TKey key = keySelector(element); - if (key == null) - { - nullList.Add(element); - if (nullCounter == -1) - { - nullCounter = counter; - counter++; - } - } - else - { - List group = ContainsGroup(groups, key, comparer); - if (group == null) - { - group = new List(); - groups.Add(key, group); - counter++; - } - group.Add(element); - } - } - - counter = 0; - foreach (KeyValuePair> group in groups) - { - if (counter == nullCounter) - { - Grouping nullGroup = new Grouping(default(TKey), nullList); - yield return nullGroup; - counter++; - } - Grouping grouping = new Grouping(group.Key, group.Value); - yield return grouping; - counter++; - } - } - - - public static IEnumerable> GroupBy(this IEnumerable source, - Func keySelector, Func elementSelector) - { - return GroupBy(source, keySelector, elementSelector); - } - - - public static IEnumerable> GroupBy(this IEnumerable source, - Func keySelector, Func elementSelector, IEqualityComparer comparer) - { - if (source == null || keySelector == null || elementSelector == null) - throw new ArgumentNullException(); - - Dictionary> groups = new Dictionary>(); - List nullList = new List(); - int counter = 0; - int nullCounter = -1; - - foreach (TSource item in source) - { - TKey key = keySelector(item); - TElement element = elementSelector(item); - if (key == null) - { - nullList.Add(element); - if (nullCounter == -1) - { - nullCounter = counter; - counter++; - } - } - else - { - List group = ContainsGroup(groups, key, comparer); - if (group == null) - { - group = new List(); - groups.Add(key, group); - counter++; - } - group.Add(element); - } - } - - counter = 0; - foreach (KeyValuePair> group in groups) - { - if (counter == nullCounter) - { - Grouping nullGroup = new Grouping(default(TKey), nullList); - yield return nullGroup; - counter++; - } - Grouping grouping = new Grouping(group.Key, group.Value); - yield return grouping; - counter++; - } - } - - #endregion - - # region GroupJoin - - public static IEnumerable GroupJoin(this IEnumerable outer, - IEnumerable inner, Func outerKeySelector, - Func innerKeySelector, Func, TResult> resultSelector) - { - return GroupJoin(outer, inner, outerKeySelector, innerKeySelector, resultSelector, null); - } - - public static IEnumerable GroupJoin(this IEnumerable outer, - IEnumerable inner, Func outerKeySelector, - Func innerKeySelector, Func, TResult> resultSelector, - IEqualityComparer comparer) - { - if (outer == null || inner == null || outerKeySelector == null || - innerKeySelector == null || resultSelector == null) - throw new ArgumentNullException(); - - if (comparer == null) - comparer = EqualityComparer.Default; - - Lookup innerKeys = ToLookup(inner, innerKeySelector, comparer); - /*Dictionary> innerKeys = new Dictionary> (); - foreach (U element in inner) - { - K innerKey = innerKeySelector (element); - if (!innerKeys.ContainsKey (innerKey)) - innerKeys.Add (innerKey, new List ()); - innerKeys[innerKey].Add (element); - }*/ - - foreach (TOuter element in outer) - { - TKey outerKey = outerKeySelector(element); - if (innerKeys.Contains(outerKey)) - yield return resultSelector(element, innerKeys[outerKey]); - } - } - - #endregion - - #region Intersect - - - public static IEnumerable Intersect(this IEnumerable first, IEnumerable second) - { - if (first == null || second == null) - throw new ArgumentNullException(); - - List items = new List(Distinct(first)); - bool[] marked = new bool[items.Count]; - for (int i = 0; i < marked.Length; i++) - marked[i] = false; - - foreach (TSource element in second) - { - int index = IndexOf(items, element); - if (index != -1) - marked[index] = true; - } - for (int i = 0; i < marked.Length; i++) - { - if (marked[i]) - yield return items[i]; - } - } - - #endregion - - # region Join - - public static IEnumerable Join(this IEnumerable outer, - IEnumerable inner, Func outerKeySelector, - Func innerKeySelector, Func resultSelector, IEqualityComparer comparer) - { - if (outer == null || inner == null || outerKeySelector == null || - innerKeySelector == null || resultSelector == null) - throw new ArgumentNullException(); - - if (comparer == null) - comparer = EqualityComparer.Default; - - Lookup innerKeys = ToLookup(inner, innerKeySelector, comparer); - /*Dictionary> innerKeys = new Dictionary> (); - foreach (U element in inner) - { - K innerKey = innerKeySelector (element); - if (!innerKeys.ContainsKey (innerKey)) - innerKeys.Add (innerKey, new List ()); - innerKeys[innerKey].Add (element); - }*/ - - foreach (TOuter element in outer) - { - TKey outerKey = outerKeySelector(element); - if (innerKeys.Contains(outerKey)) - { - foreach (TInner innerElement in innerKeys[outerKey]) - yield return resultSelector(element, innerElement); - } - } - } - - public static IEnumerable Join(this IEnumerable outer, - IEnumerable inner, Func outerKeySelector, - Func innerKeySelector, Func resultSelector) - { - return Join(outer, inner, outerKeySelector, innerKeySelector, resultSelector); - } - # endregion - - #region Last - - public static TSource Last(this IEnumerable source) - { - if (source == null) - throw new ArgumentNullException(); - - bool noElements = true; - TSource lastElement = default(TSource); - foreach (TSource element in source) - { - if (noElements) noElements = false; - lastElement = element; - } - - if (!noElements) - return lastElement; - else - throw new InvalidOperationException(); - } - - public static TSource Last(this IEnumerable source, - Func predicate) - { - if (source == null || predicate == null) - throw new ArgumentNullException(); - - bool noElements = true; - TSource lastElement = default(TSource); - foreach (TSource element in source) - { - if (predicate(element)) - { - if (noElements) noElements = false; - lastElement = element; - } - } - - if (!noElements) - return lastElement; - else - throw new InvalidOperationException(); - } - - #endregion - - #region LastOrDefault - - public static TSource LastOrDefault(this IEnumerable source) - { - if (source == null) - throw new ArgumentNullException(); - - TSource lastElement = default(TSource); - foreach (TSource element in source) - lastElement = element; - - return lastElement; - } - - public static TSource LastOrDefault(this IEnumerable source, - Func predicate) - { - if (source == null || predicate == null) - throw new ArgumentNullException(); - - TSource lastElement = default(TSource); - foreach (TSource element in source) - { - if (predicate(element)) - lastElement = element; - } - - return lastElement; - } - - #endregion - - #region LongCount - public static long LongCount(this IEnumerable source) - { - if (source == null) - throw new ArgumentNullException(); - - long counter = 0; - foreach (TSource element in source) - counter++; - return counter; - } - - - public static long LongCount(this IEnumerable source, Func selector) - { - if (source == null || selector == null) - throw new ArgumentNullException(); - - long counter = 0; - foreach (TSource element in source) - if (selector(element)) - counter++; - - return counter; - } - - #endregion - - #region Max - - public static int Max(this IEnumerable source) - { - if (source == null) - throw new ArgumentNullException(); - - int maximum = int.MinValue; - int counter = 0; - foreach (int element in source) - { - if (element > maximum) - maximum = element; - counter++; - } - - if (counter == 0) - throw new InvalidOperationException(); - else - return maximum; - } - - - public static int? Max(this IEnumerable source) - { - if (source == null) - throw new ArgumentNullException(); - - bool onlyNull = true; - int? maximum = int.MinValue; - foreach (int? element in source) - { - if (element.HasValue) - { - onlyNull = false; - if (element > maximum) - maximum = element; - } - } - return (onlyNull ? null : maximum); - } - - - public static long Max(this IEnumerable source) - { - if (source == null) - throw new ArgumentNullException(); - - long maximum = long.MinValue; - int counter = 0; - foreach (long element in source) - { - if (element > maximum) - maximum = element; - counter++; - } - - if (counter == 0) - throw new InvalidOperationException(); - else - return maximum; - } - - - public static long? Max(this IEnumerable source) - { - if (source == null) - throw new ArgumentNullException(); - - bool onlyNull = true; - long? maximum = long.MinValue; - foreach (long? element in source) - { - if (element.HasValue) - { - onlyNull = false; - if (element > maximum) - maximum = element; - } - } - return (onlyNull ? null : maximum); - } - - - public static double Max(this IEnumerable source) - { - if (source == null) - throw new ArgumentNullException(); - - double maximum = double.MinValue; - int counter = 0; - foreach (double element in source) - { - if (element > maximum) - maximum = element; - counter++; - } - - if (counter == 0) - throw new InvalidOperationException(); - else - return maximum; - } - - - public static double? Max(this IEnumerable source) - { - if (source == null) - throw new ArgumentNullException(); - - bool onlyNull = true; - double? maximum = double.MinValue; - foreach (double? element in source) - { - if (element.HasValue) - { - onlyNull = false; - if (element > maximum) - maximum = element; - } - } - return (onlyNull ? null : maximum); - } - - - public static decimal Max(this IEnumerable source) - { - if (source == null) - throw new ArgumentNullException(); - - decimal maximum = decimal.MinValue; - int counter = 0; - foreach (decimal element in source) - { - if (element > maximum) - maximum = element; - counter++; - } - - if (counter == 0) - throw new InvalidOperationException(); - else - return maximum; - } - - - public static decimal? Max(this IEnumerable source) - { - if (source == null) - throw new ArgumentNullException(); - - bool onlyNull = true; - decimal? maximum = decimal.MinValue; - foreach (decimal? element in source) - { - if (element.HasValue) - { - onlyNull = false; - if (element > maximum) - maximum = element; - } - } - return (onlyNull ? null : maximum); - } - - - public static T Max(this IEnumerable source) - { - if (source == null) - throw new ArgumentNullException(); - - bool notAssigned = true; - T maximum = default(T); - int counter = 0; - foreach (T element in source) - { - if (notAssigned) - { - maximum = element; - notAssigned = false; - } - else - { - int comparison; - if (element is IComparable) - comparison = ((IComparable)element).CompareTo(maximum); - else if (element is System.IComparable) - comparison = ((System.IComparable)element).CompareTo(maximum); - else - throw new ArgumentNullException(); - - if (comparison > 0) - maximum = element; - } - counter++; - } - - if (counter == 0) - throw new InvalidOperationException(); - else - return maximum; - } - - - public static int Max(this IEnumerable source, - Func selector) - { - if (source == null || selector == null) - throw new ArgumentNullException(); - - int maximum = int.MinValue; - int counter = 0; - foreach (T item in source) - { - int element = selector(item); - if (element > maximum) - maximum = element; - counter++; - } - - if (counter == 0) - throw new InvalidOperationException(); - else - return maximum; - } - - - public static int? Max(this IEnumerable source, - Func selector) - { - if (source == null || selector == null) - throw new ArgumentNullException(); - - bool onlyNull = true; - int? maximum = int.MinValue; - foreach (T item in source) - { - int? element = selector(item); - if (element.HasValue) - { - onlyNull = false; - if (element > maximum) - maximum = element; - } - } - return (onlyNull ? null : maximum); - } - - - public static long Max(this IEnumerable source, - Func selector) - { - if (source == null || selector == null) - throw new ArgumentNullException(); - - long maximum = long.MinValue; - int counter = 0; - foreach (TSource item in source) - { - long element = selector(item); - if (element > maximum) - maximum = element; - counter++; - } - - if (counter == 0) - throw new InvalidOperationException(); - else - return maximum; - } - - - public static long? Max(this IEnumerable source, - Func selector) - { - if (source == null || selector == null) - throw new ArgumentNullException(); - - bool onlyNull = true; - long? maximum = long.MinValue; - foreach (TSource item in source) - { - long? element = selector(item); - if (element.HasValue) - { - onlyNull = false; - if (element > maximum) - maximum = element; - } - } - return (onlyNull ? null : maximum); - } - - - public static double Max(this IEnumerable source, - Func selector) - { - if (source == null || selector == null) - throw new ArgumentNullException(); - - double maximum = double.MinValue; - int counter = 0; - foreach (TSource item in source) - { - double element = selector(item); - if (element > maximum) - maximum = element; - counter++; - } - - if (counter == 0) - throw new InvalidOperationException(); - else - return maximum; - } - - - public static double? Max(this IEnumerable source, - Func selector) - { - if (source == null || selector == null) - throw new ArgumentNullException(); - - bool onlyNull = true; - double? maximum = double.MinValue; - foreach (TSource item in source) - { - double? element = selector(item); - if (element.HasValue) - { - onlyNull = false; - if (element > maximum) - maximum = element; - } - } - return (onlyNull ? null : maximum); - } - - - public static decimal Max(this IEnumerable source, - Func selector) - { - if (source == null || selector == null) - throw new ArgumentNullException(); - - decimal maximum = decimal.MinValue; - int counter = 0; - foreach (TSource item in source) - { - decimal element = selector(item); - if (element > maximum) - maximum = element; - counter++; - } - - if (counter == 0) - throw new InvalidOperationException(); - else - return maximum; - } - - - public static decimal? Max(this IEnumerable source, - Func selector) - { - if (source == null || selector == null) - throw new ArgumentNullException(); - - bool onlyNull = true; - decimal? maximum = decimal.MinValue; - foreach (TSource item in source) - { - decimal? element = selector(item); - if (element.HasValue) - { - onlyNull = false; - if (element > maximum) - maximum = element; - } - } - return (onlyNull ? null : maximum); - } - - - public static TResult Max(this IEnumerable source, - Func selector) - { - if (source == null || selector == null) - throw new ArgumentNullException(); - - bool notAssigned = true; - TResult maximum = default(TResult); - int counter = 0; - foreach (TSource item in source) - { - TResult element = selector(item); - if (notAssigned) - { - maximum = element; - notAssigned = false; - } - else - { - int comparison; - if (element is IComparable) - comparison = ((IComparable)element).CompareTo(maximum); - else if (element is System.IComparable) - comparison = ((System.IComparable)element).CompareTo(maximum); - else - throw new ArgumentNullException(); - - if (comparison > 0) - maximum = element; - } - counter++; - } - - if (counter == 0) - throw new InvalidOperationException(); - else - return maximum; - } - - #endregion - - #region Min - - public static int Min(this IEnumerable source) - { - if (source == null) - throw new ArgumentNullException(); - - int minimum = int.MaxValue; - int counter = 0; - foreach (int element in source) - { - if (element < minimum) - minimum = element; - counter++; - } - - if (counter == 0) - throw new InvalidOperationException(); - else - return minimum; - } - - - public static int? Min(this IEnumerable source) - { - if (source == null) - throw new ArgumentNullException(); - - bool onlyNull = true; - int? minimum = int.MaxValue; - foreach (int? element in source) - { - if (element.HasValue) - { - onlyNull = false; - if (element < minimum) - minimum = element; - } - } - return (onlyNull ? null : minimum); - } - - public static long Min(this IEnumerable source) - { - if (source == null) - throw new ArgumentNullException(); - - long minimum = long.MaxValue; - int counter = 0; - foreach (long element in source) - { - if (element < minimum) - minimum = element; - counter++; - } - - if (counter == 0) - throw new InvalidOperationException(); - else - return minimum; - } - - - public static long? Min(this IEnumerable source) - { - if (source == null) - throw new ArgumentNullException(); - - bool onlyNull = true; - long? minimum = long.MaxValue; - foreach (long? element in source) - { - if (element.HasValue) - { - onlyNull = false; - if (element < minimum) - minimum = element; - } - } - return (onlyNull ? null : minimum); - } - - - public static double Min(this IEnumerable source) - { - if (source == null) - throw new ArgumentNullException(); - - double minimum = double.MaxValue; - int counter = 0; - foreach (double element in source) - { - if (element < minimum) - minimum = element; - counter++; - } - - if (counter == 0) - throw new InvalidOperationException(); - else - return minimum; - } - - - public static double? Min(this IEnumerable source) - { - if (source == null) - throw new ArgumentNullException(); - - bool onlyNull = true; - double? minimum = double.MaxValue; - foreach (double? element in source) - { - if (element.HasValue) - { - onlyNull = false; - if (element < minimum) - minimum = element; - } - } - return (onlyNull ? null : minimum); - } - - - public static decimal Min(this IEnumerable source) - { - if (source == null) - throw new ArgumentNullException(); - - decimal minimum = decimal.MaxValue; - int counter = 0; - foreach (decimal element in source) - { - if (element < minimum) - minimum = element; - counter++; - } - - if (counter == 0) - throw new InvalidOperationException(); - else - return minimum; - } - - - public static decimal? Min(this IEnumerable source) - { - if (source == null) - throw new ArgumentNullException(); - - bool onlyNull = true; - decimal? minimum = decimal.MaxValue; - foreach (decimal? element in source) - { - if (element.HasValue) - { - onlyNull = false; - if (element < minimum) - minimum = element; - } - } - return (onlyNull ? null : minimum); - } - - - public static TSource Min(this IEnumerable source) - { - if (source == null) - throw new ArgumentNullException(); - - bool notAssigned = true; - TSource minimum = default(TSource); - int counter = 0; - foreach (TSource element in source) - { - if (notAssigned) - { - minimum = element; - notAssigned = false; - } - else - { - int comparison; - if (element is IComparable) - comparison = ((IComparable)element).CompareTo(minimum); - else if (element is System.IComparable) - comparison = ((System.IComparable)element).CompareTo(minimum); - else - throw new ArgumentNullException(); - - if (comparison < 0) - minimum = element; - } - counter++; - } - - if (counter == 0) - throw new InvalidOperationException(); - else - return minimum; - } - - - public static int Min(this IEnumerable source, - Func selector) - { - if (source == null || selector == null) - throw new ArgumentNullException(); - - int minimum = int.MaxValue; - int counter = 0; - foreach (TSource item in source) - { - int element = selector(item); - if (element < minimum) - minimum = element; - counter++; - } - - if (counter == 0) - throw new InvalidOperationException(); - else - return minimum; - } - - - public static int? Min(this IEnumerable source, - Func selector) - { - if (source == null || selector == null) - throw new ArgumentNullException(); - - bool onlyNull = true; - int? minimum = int.MaxValue; - foreach (TSource item in source) - { - int? element = selector(item); - if (element.HasValue) - { - onlyNull = false; - if (element < minimum) - minimum = element; - } - } - return (onlyNull ? null : minimum); - } - - - public static long Min(this IEnumerable source, - Func selector) - { - if (source == null || selector == null) - throw new ArgumentNullException(); - - long minimum = long.MaxValue; - int counter = 0; - foreach (TSource item in source) - { - long element = selector(item); - if (element < minimum) - minimum = element; - counter++; - } - - if (counter == 0) - throw new InvalidOperationException(); - else - return minimum; - } - - - public static long? Min(this IEnumerable source, - Func selector) - { - if (source == null || selector == null) - throw new ArgumentNullException(); - - bool onlyNull = true; - long? minimum = long.MaxValue; - foreach (TSource item in source) - { - long? element = selector(item); - if (element.HasValue) - { - onlyNull = false; - if (element < minimum) - minimum = element; - } - } - return (onlyNull ? null : minimum); - } - - - public static double Min(this IEnumerable source, - Func selector) - { - if (source == null || selector == null) - throw new ArgumentNullException(); - - double minimum = double.MaxValue; - int counter = 0; - foreach (TSource item in source) - { - double element = selector(item); - if (element < minimum) - minimum = element; - counter++; - } - - if (counter == 0) - throw new InvalidOperationException(); - else - return minimum; - } - - - public static double? Min(this IEnumerable source, - Func selector) - { - if (source == null || selector == null) - throw new ArgumentNullException(); - - bool onlyNull = true; - double? minimum = double.MaxValue; - foreach (TSource item in source) - { - double? element = selector(item); - if (element.HasValue) - { - onlyNull = false; - if (element < minimum) - minimum = element; - } - } - return (onlyNull ? null : minimum); - } - - - public static decimal Min(this IEnumerable source, - Func selector) - { - if (source == null || selector == null) - throw new ArgumentNullException(); - - decimal minimum = decimal.MaxValue; - int counter = 0; - foreach (TSource item in source) - { - decimal element = selector(item); - if (element < minimum) - minimum = element; - counter++; - } - - if (counter == 0) - throw new InvalidOperationException(); - else - return minimum; - } - - - public static decimal? Min(this IEnumerable source, - Func selector) - { - if (source == null || selector == null) - throw new ArgumentNullException(); - - bool onlyNull = true; - decimal? minimum = decimal.MaxValue; - foreach (TSource item in source) - { - decimal? element = selector(item); - if (element.HasValue) - { - onlyNull = false; - if (element < minimum) - minimum = element; - } - } - return (onlyNull ? null : minimum); - } - - - public static TResult Min(this IEnumerable source, - Func selector) - { - if (source == null || selector == null) - throw new ArgumentNullException(); - - bool notAssigned = true; - TResult minimum = default(TResult); - int counter = 0; - foreach (TSource item in source) - { - TResult element = selector(item); - if (notAssigned) - { - minimum = element; - notAssigned = false; - } - else - { - int comparison; - if (element is IComparable) - comparison = ((IComparable)element).CompareTo(minimum); - else if (element is System.IComparable) - comparison = ((System.IComparable)element).CompareTo(minimum); - else - throw new ArgumentNullException(); - - if (comparison < 0) - minimum = element; - } - counter++; - } - - if (counter == 0) - throw new InvalidOperationException(); - else - return minimum; - } - - #endregion - - #region OfType - - public static IEnumerable OfType(this IEnumerable source) - { - if (source == null) - throw new ArgumentNullException(); - - foreach (object element in source) - if (element is TSource) - yield return (TSource)element; - } - - #endregion - - #region OrderBy - - public static OrderedSequence OrderBy(this IEnumerable source, - Func keySelector) - { - return OrderBy(source, keySelector, null); - } - - - public static OrderedSequence OrderBy(this IEnumerable source, - Func keySelector, - IComparer comparer) - { - if (source == null || keySelector == null) - throw new ArgumentNullException(); - - return new InternalOrderedSequence( - source, keySelector, (comparer ?? Comparer.Default), false, null); - } - - #endregion - - #region OrderByDescending - - public static OrderedSequence OrderByDescending(this IEnumerable source, - Func keySelector) - { - return OrderByDescending(source, keySelector, null); - } - - - public static OrderedSequence OrderByDescending(this IEnumerable source, - Func keySelector, IComparer comparer) - { - if (source == null || keySelector == null) - throw new ArgumentNullException(); - - return new InternalOrderedSequence( - source, keySelector, (comparer ?? Comparer.Default), true, null); - } - - #endregion - - #region Range - - public static IEnumerable Range(int start, int count) - { - if (count < 0 || (start + count - 1) > int.MaxValue) - throw new ArgumentOutOfRangeException(); - - for (int i = start; i < (start + count - 1); i++) - yield return i; - } - - #endregion - - #region Repeat - - public static IEnumerable Repeat(TResult element, int count) - { - if (count < 0) - throw new ArgumentOutOfRangeException(); - - for (int i = 0; i < count; i++) - yield return element; - } - - #endregion - - - #region Reverse - - public static IEnumerable Reverse(this IEnumerable source) - { - if (source == null) - throw new ArgumentNullException(); - - List list = new List(source); - list.Reverse(); - return list; - } - - #endregion - - #region Select - - public static IEnumerable Select(this IEnumerable source, - Func selector) - { - if (source == null || selector == null) - throw new ArgumentNullException(); - - foreach (TSource element in source) - yield return selector(element); - } - - - public static IEnumerable Select(this IEnumerable source, - Func selector) - { - if (source == null || selector == null) - throw new ArgumentNullException(); - - int counter = 0; - foreach (TSource element in source) - { - yield return selector(element, counter); - counter++; - } - } - - #endregion - - #region SelectMany - - public static IEnumerable SelectMany(this IEnumerable source, - Func> selector) - { - if (source == null || selector == null) - throw new ArgumentNullException(); - - foreach (TSource element in source) - foreach (TResult item in selector(element)) - yield return item; - } - - - public static IEnumerable SelectMany(this IEnumerable source, - Func> selector) - { - if (source == null || selector == null) - throw new ArgumentNullException(); - - int counter = 0; - foreach (TSource element in source) - { - foreach (TResult item in selector(element, counter)) - yield return item; - counter++; - } - } - - #endregion - - #region Single - - public static TSource Single(this IEnumerable source) - { - if (source == null) - throw new ArgumentNullException(); - - bool otherElement = false; - TSource singleElement = default(TSource); - foreach (TSource element in source) - { - if (otherElement) throw new InvalidOperationException(); - if (!otherElement) otherElement = true; - singleElement = element; - } - - if (otherElement) - return singleElement; - else - throw new InvalidOperationException(); - } - - - public static TSource Single(this IEnumerable source, - Func predicate) - { - if (source == null || predicate == null) - throw new ArgumentNullException(); - - bool otherElement = false; - TSource singleElement = default(TSource); - foreach (TSource element in source) - { - if (predicate(element)) - { - if (otherElement) throw new InvalidOperationException(); - if (!otherElement) otherElement = true; - singleElement = element; - } - } - - if (otherElement) - return singleElement; - else - throw new InvalidOperationException(); - } - - #endregion - - #region SingleOrDefault - - public static TSource SingleOrDefault(this IEnumerable source) - { - if (source == null) - throw new ArgumentNullException(); - - bool otherElement = false; - TSource singleElement = default(TSource); - foreach (TSource element in source) - { - if (otherElement) throw new InvalidOperationException(); - if (!otherElement) otherElement = true; - singleElement = element; - } - - return singleElement; - } - - - public static TSource SingleOrDefault(this IEnumerable source, - Func predicate) - { - if (source == null || predicate == null) - throw new ArgumentNullException(); - - bool otherElement = false; - TSource singleElement = default(TSource); - foreach (TSource element in source) - { - if (predicate(element)) - { - if (otherElement) throw new InvalidOperationException(); - if (!otherElement) otherElement = true; - singleElement = element; - } - } - - return singleElement; - } - - #endregion - - #region Skip - public static IEnumerable Skip(this IEnumerable source, int count) - { - if (source == null) - throw new NotSupportedException(); - - int i = 0; - foreach (TSource e in source) - { - if (++i < count) - continue; - yield return e; - } - } - #endregion - - #region SkipWhile - - - public static IEnumerable SkipWhile( - IEnumerable source, - Func predicate) - { - if (source == null || predicate == null) - throw new ArgumentNullException(); - - bool yield = false; - - foreach (T element in source) - { - if (yield) - yield return element; - else - if (!predicate(element)) - { - yield return element; - yield = true; - } - } - } - - - public static IEnumerable SkipWhile(this IEnumerable source, - Func predicate) - { - if (source == null || predicate == null) - throw new ArgumentNullException(); - - int counter = 0; - bool yield = false; - - foreach (TSource element in source) - { - if (yield) - yield return element; - else - if (!predicate(element, counter)) - { - yield return element; - yield = true; - } - counter++; - } - } - - #endregion - - #region Sum - - public static int Sum(this IEnumerable source) - { - if (source == null) - throw new ArgumentNullException("source"); - - int sum = 0; - foreach (int element in source) - sum += element; - - return sum; - } - - - public static int Sum(this IEnumerable source, Func selector) - { - if (source == null || selector == null) - throw new ArgumentNullException(); - - int sum = 0; - foreach (TSource element in source) - sum += selector(element); - - return sum; - } - - - public static int? Sum(this IEnumerable source) - { - if (source == null) - throw new ArgumentNullException(); - - int? sum = 0; - foreach (int? element in source) - if (element.HasValue) - sum += element.Value; - - return sum; - } - - - public static int? Sum(this IEnumerable source, Func selector) - { - if (source == null || selector == null) - throw new ArgumentNullException(); - - int? sum = 0; - foreach (TSource element in source) - { - int? item = selector(element); - if (item.HasValue) - sum += item.Value; - } - - return sum; - } - - - public static long Sum(this IEnumerable source) - { - if (source == null) - throw new ArgumentNullException(); - - long sum = 0; - foreach (long element in source) - sum += element; - - return sum; - } - - - public static long Sum(this IEnumerable source, Func selector) - { - if (source == null || selector == null) - throw new ArgumentNullException(); - - long sum = 0; - foreach (TSource element in source) - sum += selector(element); - - return sum; - } - - - public static long? Sum(this IEnumerable source) - { - if (source == null) - throw new ArgumentNullException(); - - long? sum = 0; - foreach (long? element in source) - if (element.HasValue) - sum += element.Value; - - return sum; - } - - - public static long? Sum(this IEnumerable source, Func selector) - { - if (source == null || selector == null) - throw new ArgumentNullException(); - - long? sum = 0; - foreach (TSource element in source) - { - long? item = selector(element); - if (item.HasValue) - sum += item.Value; - } - - return sum; - } - - - public static double Sum(this IEnumerable source) - { - if (source == null) - throw new ArgumentNullException(); - - double sum = 0; - foreach (double element in source) - sum += element; - - return sum; - } - - - public static double Sum(this IEnumerable source, Func selector) - { - if (source == null || selector == null) - throw new ArgumentNullException(); - - double sum = 0; - foreach (TSource element in source) - sum += selector(element); - - return sum; - } - - - public static double? Sum(this IEnumerable source) - { - if (source == null) - throw new ArgumentNullException(); - - double? sum = 0; - foreach (double? element in source) - if (element.HasValue) - sum += element.Value; - - return sum; - } - - - public static double? Sum(this IEnumerable source, Func selector) - { - if (source == null || selector == null) - throw new ArgumentNullException(); - - double? sum = 0; - foreach (TSource element in source) - { - double? item = selector(element); - if (item.HasValue) - sum += item.Value; - } - - return sum; - } - - - public static decimal Sum(this IEnumerable source) - { - if (source == null) - throw new ArgumentNullException(); - - decimal sum = 0; - foreach (decimal element in source) - sum += element; - - return sum; - } - - - public static decimal Sum(this IEnumerable source, Func selector) - { - if (source == null || selector == null) - throw new ArgumentNullException(); - - decimal sum = 0; - foreach (TSource element in source) - sum += selector(element); - - return sum; - } - - - public static decimal? Sum(this IEnumerable source) - { - if (source == null) - throw new ArgumentNullException(); - - decimal? sum = 0; - foreach (decimal? element in source) - if (element.HasValue) - sum += element.Value; - - return sum; - } - - - public static decimal? Sum(this IEnumerable source, Func selector) - { - if (source == null || selector == null) - throw new ArgumentNullException(); - - decimal? sum = 0; - foreach (TSource element in source) - { - decimal? item = selector(element); - if (item.HasValue) - sum += item.Value; - } - - return sum; - } - - #endregion - #region Take - - public static IEnumerable Take(this IEnumerable source, int count) - { - if (source == null) - throw new ArgumentNullException(); - - if (count <= 0) - yield break; - else - { - int counter = 0; - foreach (T element in source) - { - yield return element; - counter++; - if (counter == count) - yield break; - } - } - } - - #endregion - - #region TakeWhile - - public static IEnumerable TakeWhile(this IEnumerable source, Func predicate) - { - if (source == null || predicate == null) - throw new ArgumentNullException(); - - foreach (T element in source) - { - if (predicate(element)) - yield return element; - else - yield break; - } - } - - public static IEnumerable TakeWhile(this IEnumerable source, Func predicate) - { - if (source == null || predicate == null) - throw new ArgumentNullException(); - - int counter = 0; - foreach (TSource element in source) - { - if (predicate(element, counter)) - yield return element; - else - yield break; - counter++; - } - } - - #endregion - - #region ThenBy - - public static OrderedSequence ThenBy(this OrderedSequence source, Func keySelector) - { - return ThenBy(source, keySelector, null); - } - - - public static OrderedSequence ThenBy(this OrderedSequence source, - Func keySelector, IComparer comparer) - { - if (source == null || keySelector == null) - throw new ArgumentNullException(); - - return new InternalOrderedSequence( - source, keySelector, (comparer ?? Comparer.Default), false, source); - } - - #endregion - - #region ThenByDescending - - public static OrderedSequence ThenByDescending(this OrderedSequence source, - Func keySelector) - { - return ThenByDescending(source, keySelector, null); - } - - - public static OrderedSequence ThenByDescending(this OrderedSequence source, - Func keySelector, IComparer comparer) - { - if (source == null || keySelector == null) - throw new ArgumentNullException(); - - return new InternalOrderedSequence( - source, keySelector, (comparer ?? Comparer.Default), true, source); - } - - #endregion - - #region ToArray - public static T[] ToArray (this IEnumerable source) - { - if (source == null) - throw new ArgumentNullException (); - - List list = new List (source); - return list.ToArray (); - } - - #endregion - - #region ToDictionary - public static Dictionary ToDictionary(this IEnumerable source, Func keySelector, Func elementSelector) - { - return ToDictionary(source, keySelector, elementSelector, null); - } - - - public static Dictionary ToDictionary(this IEnumerable source, Func keySelector, Func elementSelector, IEqualityComparer comparer) - { - if (source == null) - throw new ArgumentNullException("source"); - if (keySelector == null) - throw new ArgumentNullException("keySelector"); - if (elementSelector == null) - throw new ArgumentNullException("elementSelector"); - - Dictionary dict = new Dictionary(comparer); - foreach (TSource e in source) - { - dict.Add(keySelector(e), elementSelector(e)); - } - - return dict; - } - #endregion - - #region ToList - public static List ToList(this IEnumerable source) - { - if (source == null) - throw new ArgumentNullException("source"); - - return new List(source); - } - #endregion - - #region ToLookup - - public static Lookup ToLookup(this IEnumerable source, Func keySelector) - { - return ToLookup(source, keySelector, null); - } - - - public static Lookup ToLookup(this IEnumerable source, - Func keySelector, IEqualityComparer comparer) - { - if (source == null || keySelector == null) - throw new ArgumentNullException(); - - Dictionary> dictionary = new Dictionary>(comparer ?? EqualityComparer.Default); - foreach (TSource element in source) - { - TKey key = keySelector(element); - if (key == null) - throw new ArgumentNullException(); - if (!dictionary.ContainsKey(key)) - dictionary.Add(key, new List()); - dictionary[key].Add(element); - } - return new Lookup(dictionary); - } - - - public static Lookup ToLookup(this IEnumerable source, - Func keySelector, Func elementSelector) - { - return ToLookup(source, keySelector, elementSelector, null); - } - - - public static Lookup ToLookup(this IEnumerable source, - Func keySelector, Func elementSelector, IEqualityComparer comparer) - { - if (source == null || keySelector == null || elementSelector == null) - throw new ArgumentNullException(); - - Dictionary> dictionary = new Dictionary>(comparer ?? EqualityComparer.Default); - foreach (TSource element in source) - { - TKey key = keySelector(element); - if (key == null) - throw new ArgumentNullException(); - if (!dictionary.ContainsKey(key)) - dictionary.Add(key, new List()); - dictionary[key].Add(elementSelector(element)); - } - return new Lookup(dictionary); - } - - #endregion - - #region ToSequence - - public static IEnumerable ToSequence(this IEnumerable source) - { - return (IEnumerable)source; - } - - #endregion - - #region Union - - - public static IEnumerable Union(this IEnumerable first, IEnumerable second) - { - if (first == null || second == null) - throw new ArgumentNullException(); - - List items = new List(); - foreach (T element in first) - { - if (IndexOf(items, element) == -1) - { - items.Add(element); - yield return element; - } - } - foreach (T element in second) - { - if (IndexOf(items, element) == -1) - { - items.Add(element); - yield return element; - } - } - } - - #endregion - - #region Where - - public static IEnumerable Where(this IEnumerable source, - Func predicate) - { - if (source == null || predicate == null) - throw new ArgumentNullException(); - - foreach (TSource element in source) - if (predicate(element)) - yield return element; - } - - - public static IEnumerable Where(this IEnumerable source, - Func predicate) - { - if (source == null || predicate == null) - throw new ArgumentNullException(); - - int counter = 0; - foreach (TSource element in source) - { - if (predicate(element, counter)) - yield return element; - counter++; - } - } - - #endregion - - // These methods are not included in the - // .NET Standard Query Operators Specification, - // but they provide additional useful commands - - #region Compare - - private static bool Equals(T first, T second) - { - // Mostly, values in Enumerable - // sequences need to be compared using - // Equals and GetHashCode - - if (first == null || second == null) - return (first == null && second == null); - else - return ((first.Equals(second) || - first.GetHashCode() == second.GetHashCode())); - } - - #endregion - - #region IndexOf - - public static int IndexOf(this IEnumerable source, T item, IEqualityComparer comparer) - { - if (comparer == null) - comparer = EqualityComparer.Default; - - int counter = 0; - foreach (T element in source) - { - if (comparer.Equals(element, item)) - return counter; - counter++; - } - // The item was not found - return -1; - } - - public static int IndexOf(this IEnumerable source, T item) - { - return IndexOf(source, item, null); - } - #endregion - - #region ToReadOnlyCollection - internal static ReadOnlyCollection ToReadOnlyCollection(IEnumerable source) - { - if (source == null) - return new ReadOnlyCollection(new List()); - - if (typeof(ReadOnlyCollection).IsInstanceOfType(source)) - return source as ReadOnlyCollection; - - return new ReadOnlyCollection(ToArray(source)); - } - #endregion - } +// +// Enumerable.cs +// +// Authors: +// Marek Safar (marek.safar@gmail.com) +// Antonello Provenzano +// Alejandro Serrano "Serras" (trupill@yahoo.es) +// Jb Evain (jbevain@novell.com) +// +// Copyright (C) 2007 Novell, Inc (http://www.novell.com) +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +// precious: http://www.hookedonlinq.com + +using System; +using System.Collections; +using System.Collections.Generic; +using System.Collections.ObjectModel; + +namespace System.Linq +{ + public static class Enumerable + { + enum Fallback { + Default, + Throw + } + + class PredicateOf { + public static readonly Func Always = (t) => true; + } + + class Function { + public static readonly Func Identity = (t) => t; + } + + #region Aggregate + + public static TSource Aggregate (this IEnumerable source, Func func) + { + Check.SourceAndFunc (source, func); + + // custom foreach so that we can efficiently throw an exception + // if zero elements and treat the first element differently + using (var enumerator = source.GetEnumerator ()) { + if (!enumerator.MoveNext ()) + throw new InvalidOperationException ("No elements in source list"); + + TSource folded = enumerator.Current; + while (enumerator.MoveNext ()) + folded = func (folded, enumerator.Current); + return folded; + } + } + + public static TAccumulate Aggregate (this IEnumerable source, + TAccumulate seed, Func func) + { + Check.SourceAndFunc (source, func); + + TAccumulate folded = seed; + foreach (TSource element in source) + folded = func (folded, element); + + return folded; + } + + public static TResult Aggregate (this IEnumerable source, TAccumulate seed, Func func, Func resultSelector) + { + Check.SourceAndFunc (source, func); + if (resultSelector == null) + throw new ArgumentNullException ("resultSelector"); + + var result = seed; + foreach (var e in source) + result = func (result, e); + + return resultSelector (result); + } + + #endregion + + #region All + + public static bool All (this IEnumerable source, Func predicate) + { + Check.SourceAndPredicate (source, predicate); + + foreach (var element in source) + if (!predicate (element)) + return false; + + return true; + } + + #endregion + + #region Any + + public static bool Any (this IEnumerable source) + { + Check.Source (source); + + var collection = source as ICollection; + if (collection != null) + return collection.Count > 0; + + using (var enumerator = source.GetEnumerator ()) + return enumerator.MoveNext (); + } + + public static bool Any (this IEnumerable source, Func predicate) + { + Check.SourceAndPredicate (source, predicate); + + foreach (TSource element in source) + if (predicate (element)) + return true; + + return false; + } + + #endregion + + #region AsEnumerable + + public static IEnumerable AsEnumerable (this IEnumerable source) + { + return source; + } + + #endregion + + #region Average + + public static double Average (this IEnumerable source) + { + return Average (source, (a, b) => a + b, (a, b) => (double) a / (double) b); + } + + public static double Average (this IEnumerable source) + { + return Average (source, (a, b) => a + b, (a, b) => (double) a / (double) b); + } + + public static double Average (this IEnumerable source) + { + return Average (source, (a, b) => a + b, (a, b) => a / b); + } + + public static float Average (this IEnumerable source) + { + return Average (source, (a, b) => a + b, (a, b) => (float) a / (float) b); + } + + public static decimal Average (this IEnumerable source) + { + return Average (source, (a, b) => a + b, (a, b) => a / b); + } + + static TResult Average (this IEnumerable source, + Func func, Func result) + where TElement : struct + where TAggregate : struct + where TResult : struct + { + Check.Source (source); + + var total = default (TAggregate); + long counter = 0; + foreach (var element in source) { + total = func (total, element); + ++counter; + } + + if (counter == 0) + throw new InvalidOperationException (); + + return result (total, counter); + } + + static TResult? AverageNullable (this IEnumerable source, + Func func, Func result) + where TElement : struct + where TAggregate : struct + where TResult : struct + { + Check.Source (source); + + var total = default (TAggregate); + long counter = 0; + foreach (var element in source) { + if (!element.HasValue) + continue; + + total = func (total, element.Value); + counter++; + } + + if (counter == 0) + return null; + + return new TResult? (result (total, counter)); + } + + public static double? Average (this IEnumerable source) + { + Check.Source (source); + + return source.AverageNullable ((a, b) => a + b, (a, b) => (double) a / (double) b); + } + + public static double? Average (this IEnumerable source) + { + Check.Source (source); + + return source.AverageNullable ((a, b) => a + b, (a, b) => (double) a / b); + } + + public static double? Average (this IEnumerable source) + { + Check.Source (source); + + return source.AverageNullable ((a, b) => a + b, (a, b) => a / b); + } + + public static decimal? Average (this IEnumerable source) + { + Check.Source (source); + + return source.AverageNullable ((a, b) => a + b, (a, b) => a / b); + } + + public static float? Average (this IEnumerable source) + { + Check.Source (source); + + return source.AverageNullable ((a, b) => a + b, (a, b) => (float) a / (float) b); + } + + public static double Average (this IEnumerable source, Func selector) + { + Check.SourceAndSelector (source, selector); + + return source.Select (selector).Average ((a, b) => a + b, (a, b) => (double) a / (double) b); + } + + public static double? Average (this IEnumerable source, Func selector) + { + Check.SourceAndSelector (source, selector); + + return source.Select (selector).AverageNullable ((a, b) => a + b, (a, b) => (double) a / (double) b); + } + + public static double Average (this IEnumerable source, Func selector) + { + Check.SourceAndSelector (source, selector); + + return source.Select (selector).Average ((a, b) => a + b, (a, b) => (double) a / (double) b); + } + + public static double? Average (this IEnumerable source, Func selector) + { + Check.SourceAndSelector (source, selector); + + return source.Select (selector).AverageNullable ((a, b) => a + b, (a, b) => (double) a / (double) b); + } + + public static double Average (this IEnumerable source, Func selector) + { + Check.SourceAndSelector (source, selector); + + return source.Select (selector).Average ((a, b) => a + b, (a, b) => a / b); + } + + public static double? Average (this IEnumerable source, Func selector) + { + Check.SourceAndSelector (source, selector); + + return source.Select (selector).AverageNullable ((a, b) => a + b, (a, b) => a / b); + } + + public static float Average (this IEnumerable source, Func selector) + { + Check.SourceAndSelector (source, selector); + + return source.Select (selector).Average ((a, b) => a + b, (a, b) => (float) a / (float) b); + } + + public static float? Average (this IEnumerable source, Func selector) + { + Check.SourceAndSelector (source, selector); + + return source.Select (selector).AverageNullable ((a, b) => a + b, (a, b) => (float) a / (float) b); + } + + public static decimal Average (this IEnumerable source, Func selector) + { + Check.SourceAndSelector (source, selector); + + return source.Select (selector).Average ((a, b) => a + b, (a, b) => a / b); + } + + public static decimal? Average (this IEnumerable source, Func selector) + { + Check.SourceAndSelector (source, selector); + + return source.Select (selector).AverageNullable ((a, b) => a + b, (a, b) => a / b); + } + + #endregion + + #region Cast + + public static IEnumerable Cast (this IEnumerable source) + { + Check.Source (source); + + return CreateCastIterator (source); + } + + static IEnumerable CreateCastIterator (IEnumerable source) + { + foreach (TResult element in source) + yield return element; + } + + #endregion + + #region Concat + + public static IEnumerable Concat (this IEnumerable first, IEnumerable second) + { + Check.FirstAndSecond (first, second); + + return CreateConcatIterator (first, second); + } + + static IEnumerable CreateConcatIterator (IEnumerable first, IEnumerable second) + { + foreach (TSource element in first) + yield return element; + foreach (TSource element in second) + yield return element; + } + + #endregion + + #region Contains + + public static bool Contains (this IEnumerable source, TSource value) + { + var collection = source as ICollection; + if (collection != null) + return collection.Contains (value); + + return Contains (source, value, null); + } + + public static bool Contains (this IEnumerable source, TSource value, IEqualityComparer comparer) + { + Check.Source (source); + + if (comparer == null) + comparer = EqualityComparer.Default; + + foreach (var element in source) + if (comparer.Equals (element, value)) + return true; + + return false; + } + #endregion + + #region Count + + public static int Count (this IEnumerable source) + { + Check.Source (source); + + var collection = source as ICollection; + if (collection != null) + return collection.Count; + + int counter = 0; + using (var enumerator = source.GetEnumerator ()) + while (enumerator.MoveNext ()) + counter++; + + return counter; + } + + public static int Count (this IEnumerable source, Func selector) + { + Check.SourceAndSelector (source, selector); + + int counter = 0; + foreach (var element in source) + if (selector (element)) + counter++; + + return counter; + } + + #endregion + + #region DefaultIfEmpty + + public static IEnumerable DefaultIfEmpty (this IEnumerable source) + { + return DefaultIfEmpty (source, default (TSource)); + } + + public static IEnumerable DefaultIfEmpty (this IEnumerable source, TSource defaultValue) + { + Check.Source (source); + + return CreateDefaultIfEmptyIterator (source, defaultValue); + } + + static IEnumerable CreateDefaultIfEmptyIterator (IEnumerable source, TSource defaultValue) + { + bool empty = true; + foreach (TSource item in source) { + empty = false; + yield return item; + } + + if (empty) + yield return defaultValue; + } + + #endregion + + #region Distinct + + public static IEnumerable Distinct (this IEnumerable source) + { + return Distinct (source, null); + } + + public static IEnumerable Distinct (this IEnumerable source, IEqualityComparer comparer) + { + Check.Source (source); + + if (comparer == null) + comparer = EqualityComparer.Default; + + return CreateDistinctIterator (source, comparer); + } + + static IEnumerable CreateDistinctIterator (IEnumerable source, IEqualityComparer comparer) + { + var items = new HashSet (comparer); + foreach (var element in source) { + if (! items.Contains (element)) { + items.Add (element); + yield return element; + } + } + } + + #endregion + + #region ElementAt + + static TSource ElementAt (this IEnumerable source, int index, Fallback fallback) + { + long counter = 0L; + + foreach (var element in source) { + if (index == counter++) + return element; + } + + if (fallback == Fallback.Throw) + throw new ArgumentOutOfRangeException (); + + return default (TSource); + } + + public static TSource ElementAt (this IEnumerable source, int index) + { + Check.Source (source); + + if (index < 0) + throw new ArgumentOutOfRangeException (); + + var list = source as IList; + if (list != null) + return list [index]; + + return source.ElementAt (index, Fallback.Throw); + } + + #endregion + + #region ElementAtOrDefault + + public static TSource ElementAtOrDefault (this IEnumerable source, int index) + { + Check.Source (source); + + if (index < 0) + return default (TSource); + + var list = source as IList; + if (list != null) + return index < list.Count ? list [index] : default (TSource); + + return source.ElementAt (index, Fallback.Default); + } + + #endregion + + #region Empty + + public static IEnumerable Empty () + { + return new TResult [0]; + } + + #endregion + + #region Except + + public static IEnumerable Except (this IEnumerable first, IEnumerable second) + { + return Except (first, second, null); + } + + public static IEnumerable Except (this IEnumerable first, IEnumerable second, IEqualityComparer comparer) + { + Check.FirstAndSecond (first, second); + + if (comparer == null) + comparer = EqualityComparer.Default; + + return CreateExceptIterator (first, second, comparer); + } + + static IEnumerable CreateExceptIterator (IEnumerable first, IEnumerable second, IEqualityComparer comparer) + { + var items = new HashSet (second, comparer); + foreach (var element in first) { + if (!items.Contains (element, comparer)) + yield return element; + } + } + + #endregion + + #region First + + static TSource First (this IEnumerable source, Func predicate, Fallback fallback) + { + foreach (var element in source) + if (predicate (element)) + return element; + + if (fallback == Fallback.Throw) + throw new InvalidOperationException (); + + return default (TSource); + } + + public static TSource First (this IEnumerable source) + { + Check.Source (source); + + var list = source as IList; + if (list != null) { + if (list.Count != 0) + return list [0]; + + throw new InvalidOperationException (); + } else { + using (var enumerator = source.GetEnumerator ()) { + if (enumerator.MoveNext ()) + return enumerator.Current; + } + } + + throw new InvalidOperationException (); + } + + public static TSource First (this IEnumerable source, Func predicate) + { + Check.SourceAndPredicate (source, predicate); + + return source.First (predicate, Fallback.Throw); + } + + #endregion + + #region FirstOrDefault + + public static TSource FirstOrDefault (this IEnumerable source) + { + Check.Source (source); + + return source.First (PredicateOf.Always, Fallback.Default); + } + + public static TSource FirstOrDefault (this IEnumerable source, Func predicate) + { + Check.SourceAndPredicate (source, predicate); + + return source.First (predicate, Fallback.Default); + } + + #endregion + + #region GroupBy + + private static List ContainsGroup ( + Dictionary> items, K key, IEqualityComparer comparer) + { + IEqualityComparer comparerInUse = (comparer ?? EqualityComparer.Default); + foreach (KeyValuePair> value in items) { + if (comparerInUse.Equals (value.Key, key)) + return value.Value; + } + return null; + } + + public static IEnumerable> GroupBy (this IEnumerable source, + Func keySelector) + { + return GroupBy (source, keySelector, null); + } + + public static IEnumerable> GroupBy (this IEnumerable source, + Func keySelector, IEqualityComparer comparer) + { + Check.SourceAndKeySelector (source, keySelector); + + return CreateGroupByIterator (source, keySelector, comparer); + } + + static IEnumerable> CreateGroupByIterator (this IEnumerable source, + Func keySelector, IEqualityComparer comparer) + { + Dictionary> groups = new Dictionary> (); + List nullList = new List (); + int counter = 0; + int nullCounter = -1; + + foreach (TSource element in source) { + TKey key = keySelector (element); + if (key == null) { + nullList.Add (element); + if (nullCounter == -1) { + nullCounter = counter; + counter++; + } + } else { + List group = ContainsGroup (groups, key, comparer); + if (group == null) { + group = new List (); + groups.Add (key, group); + counter++; + } + group.Add (element); + } + } + + counter = 0; + foreach (KeyValuePair> group in groups) { + if (counter == nullCounter) { + Grouping nullGroup = new Grouping (default (TKey), nullList); + yield return nullGroup; + counter++; + } + Grouping grouping = new Grouping (group.Key, group.Value); + yield return grouping; + counter++; + } + } + + public static IEnumerable> GroupBy (this IEnumerable source, + Func keySelector, Func elementSelector) + { + return GroupBy (source, keySelector, elementSelector, null); + } + + public static IEnumerable> GroupBy (this IEnumerable source, + Func keySelector, Func elementSelector, IEqualityComparer comparer) + { + Check.SourceAndKeyElementSelectors (source, keySelector, elementSelector); + + Dictionary> groups = new Dictionary> (); + List nullList = new List (); + int counter = 0; + int nullCounter = -1; + + foreach (TSource item in source) { + TKey key = keySelector (item); + TElement element = elementSelector (item); + if (key == null) { + nullList.Add (element); + if (nullCounter == -1) { + nullCounter = counter; + counter++; + } + } else { + List group = ContainsGroup (groups, key, comparer); + if (group == null) { + group = new List (); + groups.Add (key, group); + counter++; + } + group.Add (element); + } + } + + counter = 0; + foreach (KeyValuePair> group in groups) { + if (counter == nullCounter) { + Grouping nullGroup = new Grouping (default (TKey), nullList); + yield return nullGroup; + counter++; + } + Grouping grouping = new Grouping (group.Key, group.Value); + yield return grouping; + counter++; + } + } + + public static IEnumerable GroupBy (this IEnumerable source, + Func keySelector, Func elementSelector, + Func, TResult> resultSelector) + { + return GroupBy (source, keySelector, elementSelector, resultSelector, null); + } + + public static IEnumerable GroupBy (this IEnumerable source, + Func keySelector, Func elementSelector, + Func, TResult> resultSelector, + IEqualityComparer comparer) + { + IEnumerable> groups = GroupBy ( + source, keySelector, elementSelector, comparer); + + foreach (IGrouping group in groups) + yield return resultSelector (group.Key, group); + } + + public static IEnumerable GroupBy (this IEnumerable source, + Func keySelector, + Func, TResult> resultSelector) + { + return GroupBy (source, keySelector, resultSelector, null); + } + + public static IEnumerable GroupBy (this IEnumerable source, + Func keySelector, + Func, TResult> resultSelector, + IEqualityComparer comparer) + { + IEnumerable> groups = GroupBy (source, keySelector, comparer); + + foreach (IGrouping group in groups) + yield return resultSelector (group.Key, group); + } + + #endregion + + # region GroupJoin + + public static IEnumerable GroupJoin (this IEnumerable outer, + IEnumerable inner, Func outerKeySelector, + Func innerKeySelector, Func, TResult> resultSelector) + { + return GroupJoin (outer, inner, outerKeySelector, innerKeySelector, resultSelector, null); + } + + public static IEnumerable GroupJoin (this IEnumerable outer, + IEnumerable inner, Func outerKeySelector, + Func innerKeySelector, Func, TResult> resultSelector, + IEqualityComparer comparer) + { + Check.JoinSelectors (outer, inner, outerKeySelector, innerKeySelector, resultSelector); + + if (comparer == null) + comparer = EqualityComparer.Default; + + return CreateGroupJoinIterator (outer, inner, outerKeySelector, innerKeySelector, resultSelector, comparer); + } + + static IEnumerable CreateGroupJoinIterator (this IEnumerable outer, + IEnumerable inner, Func outerKeySelector, + Func innerKeySelector, Func, TResult> resultSelector, + IEqualityComparer comparer) + { + ILookup innerKeys = ToLookup (inner, innerKeySelector, comparer); + /*Dictionary> innerKeys = new Dictionary> (); + foreach (U element in inner) + { + K innerKey = innerKeySelector (element); + if (!innerKeys.ContainsKey (innerKey)) + innerKeys.Add (innerKey, new List ()); + innerKeys[innerKey].Add (element); + }*/ + + foreach (TOuter element in outer) { + TKey outerKey = outerKeySelector (element); + if (innerKeys.Contains (outerKey)) + yield return resultSelector (element, innerKeys [outerKey]); + else + yield return resultSelector (element, Empty ()); + } + } + + #endregion + + #region Intersect + + public static IEnumerable Intersect (this IEnumerable first, IEnumerable second) + { + return Intersect (first, second, null); + } + + public static IEnumerable Intersect (this IEnumerable first, IEnumerable second, IEqualityComparer comparer) + { + Check.FirstAndSecond (first, second); + + if (comparer == null) + comparer = EqualityComparer.Default; + + return CreateIntersectIterator (first, second, comparer); + } + + static IEnumerable CreateIntersectIterator (IEnumerable first, IEnumerable second, IEqualityComparer comparer) + { + var items = new HashSet (second, comparer); + foreach (TSource element in first) { + if (items.Remove (element)) + yield return element; + } + } + + #endregion + + # region Join + + public static IEnumerable Join (this IEnumerable outer, + IEnumerable inner, Func outerKeySelector, + Func innerKeySelector, Func resultSelector, IEqualityComparer comparer) + { + Check.JoinSelectors (outer, inner, outerKeySelector, innerKeySelector, resultSelector); + + if (comparer == null) + comparer = EqualityComparer.Default; + + return CreateJoinIterator (outer, inner, outerKeySelector, innerKeySelector, resultSelector, comparer); + } + + static IEnumerable CreateJoinIterator (this IEnumerable outer, + IEnumerable inner, Func outerKeySelector, + Func innerKeySelector, Func resultSelector, IEqualityComparer comparer) + { + ILookup innerKeys = ToLookup (inner, innerKeySelector, comparer); + /*Dictionary> innerKeys = new Dictionary> (); + foreach (U element in inner) + { + K innerKey = innerKeySelector (element); + if (!innerKeys.ContainsKey (innerKey)) + innerKeys.Add (innerKey, new List ()); + innerKeys[innerKey].Add (element); + }*/ + + foreach (TOuter element in outer) { + TKey outerKey = outerKeySelector (element); + if (innerKeys.Contains (outerKey)) { + foreach (TInner innerElement in innerKeys [outerKey]) + yield return resultSelector (element, innerElement); + } + } + } + + public static IEnumerable Join (this IEnumerable outer, + IEnumerable inner, Func outerKeySelector, + Func innerKeySelector, Func resultSelector) + { + return outer.Join (inner, outerKeySelector, innerKeySelector, resultSelector, null); + } + + #endregion + + #region Last + + static TSource Last (this IEnumerable source, Func predicate, Fallback fallback) + { + var empty = true; + var item = default (TSource); + + foreach (var element in source) { + if (!predicate (element)) + continue; + + item = element; + empty = false; + } + + if (!empty) + return item; + + if (fallback == Fallback.Throw) + throw new InvalidOperationException (); + + return item; + } + + public static TSource Last (this IEnumerable source) + { + Check.Source (source); + + var collection = source as ICollection; + if (collection != null && collection.Count == 0) + throw new InvalidOperationException (); + + var list = source as IList; + if (list != null) + return list [list.Count - 1]; + + return source.Last (PredicateOf.Always, Fallback.Throw); + } + + public static TSource Last (this IEnumerable source, Func predicate) + { + Check.SourceAndPredicate (source, predicate); + + return source.Last (predicate, Fallback.Throw); + } + + #endregion + + #region LastOrDefault + + public static TSource LastOrDefault (this IEnumerable source) + { + Check.Source (source); + + var list = source as IList; + if (list != null) + return list.Count > 0 ? list [list.Count - 1] : default (TSource); + + return source.Last (PredicateOf.Always, Fallback.Default); + } + + public static TSource LastOrDefault (this IEnumerable source, Func predicate) + { + Check.SourceAndPredicate (source, predicate); + + return source.Last (predicate, Fallback.Default); + } + + #endregion + + #region LongCount + + public static long LongCount (this IEnumerable source) + { + Check.Source (source); + +#if !NET_2_1 + var array = source as TSource []; + if (array != null) + return array.LongLength; +#endif + + long counter = 0; + using (var enumerator = source.GetEnumerator ()) + while (enumerator.MoveNext ()) + counter++; + + return counter; + } + + public static long LongCount (this IEnumerable source, Func selector) + { + Check.SourceAndSelector (source, selector); + + long counter = 0; + foreach (TSource element in source) + if (selector (element)) + counter++; + + return counter; + } + + #endregion + + #region Max + + public static int Max (this IEnumerable source) + { + Check.Source (source); + + return Iterate (source, int.MinValue, (a, b) => Math.Max (a, b)); + } + + public static long Max (this IEnumerable source) + { + Check.Source (source); + + return Iterate (source, long.MinValue, (a, b) => Math.Max (a, b)); + } + + public static double Max (this IEnumerable source) + { + Check.Source (source); + + return Iterate (source, double.MinValue, (a, b) => Math.Max (a, b)); + } + + public static float Max (this IEnumerable source) + { + Check.Source (source); + + return Iterate (source, float.MinValue, (a, b) => Math.Max (a, b)); + } + + public static decimal Max (this IEnumerable source) + { + Check.Source (source); + + return Iterate (source, decimal.MinValue, (a, b) => Math.Max (a, b)); + } + + public static int? Max (this IEnumerable source) + { + Check.Source (source); + + return IterateNullable (source, (a, b) => Math.Max (a, b)); + } + + public static long? Max (this IEnumerable source) + { + Check.Source (source); + + return IterateNullable (source, (a, b) => Math.Max (a, b)); + } + + public static double? Max (this IEnumerable source) + { + Check.Source (source); + + return IterateNullable (source, (a, b) => Math.Max (a, b)); + } + + public static float? Max (this IEnumerable source) + { + Check.Source (source); + + return IterateNullable (source, (a, b) => Math.Max (a, b)); + } + + public static decimal? Max (this IEnumerable source) + { + Check.Source (source); + + return IterateNullable (source, (a, b) => Math.Max (a, b)); + } + + static T? IterateNullable (IEnumerable source, Func selector) where T : struct + { + bool empty = true; + T? value = null; + foreach (var element in source) { + if (!element.HasValue) + continue; + + if (!value.HasValue) + value = element.Value; + else + value = selector (element.Value, value.Value); + + empty = false; + } + + if (empty) + return null; + + return value; + } + + static TRet? IterateNullable ( + IEnumerable source, + Func source_selector, + Func selector) where TRet : struct + { + bool empty = true; + TRet? value = null; + foreach (var element in source) { + TRet? item = source_selector (element); + + if (!value.HasValue) + value = item; + else if (selector (item, value)) + value = item; + + empty = false; + } + + if (empty) + return null; + + return value; + } + + public static TSource Max (this IEnumerable source) + { + Check.Source (source); + + bool notAssigned = true; + TSource maximum = default (TSource); + int counter = 0; + foreach (TSource element in source) { + if (notAssigned) { + maximum = element; + notAssigned = false; + } else { + int comparison; + if (element is IComparable) + comparison = ((IComparable) element).CompareTo (maximum); + else if (element is System.IComparable) + comparison = ((System.IComparable) element).CompareTo (maximum); + else + throw new ArgumentNullException (); + + if (comparison > 0) + maximum = element; + } + counter++; + } + + if (counter == 0) + throw new InvalidOperationException (); + else + return maximum; + } + + public static int Max (this IEnumerable source, Func selector) + { + Check.SourceAndSelector (source, selector); + + return Iterate (source, int.MinValue, (a, b) => Math.Max (selector (a), b)); + } + + public static long Max (this IEnumerable source, Func selector) + { + Check.SourceAndSelector (source, selector); + + return Iterate (source, long.MinValue, (a, b) => Math.Max (selector (a), b)); + } + + public static double Max (this IEnumerable source, Func selector) + { + Check.SourceAndSelector (source, selector); + + return Iterate (source, double.MinValue, (a, b) => Math.Max (selector (a), b)); + } + + public static float Max (this IEnumerable source, Func selector) + { + Check.SourceAndSelector (source, selector); + + return Iterate (source, float.MinValue, (a, b) => Math.Max (selector (a), b)); + } + + public static decimal Max (this IEnumerable source, Func selector) + { + Check.SourceAndSelector (source, selector); + + return Iterate (source, decimal.MinValue, (a, b) => Math.Max (selector (a), b)); + } + + static U Iterate (IEnumerable source, U initValue, Func selector) + { + bool empty = true; + foreach (var element in source) { + initValue = selector (element, initValue); + empty = false; + } + + if (empty) + throw new InvalidOperationException (); + + return initValue; + } + + public static int? Max (this IEnumerable source, Func selector) + { + Check.SourceAndSelector (source, selector); + + return IterateNullable (source, selector, (a, b) => a > b); + } + + public static long? Max (this IEnumerable source, Func selector) + { + Check.SourceAndSelector (source, selector); + + return IterateNullable (source, selector, (a, b) => a > b); + } + + public static double? Max (this IEnumerable source, Func selector) + { + Check.SourceAndSelector (source, selector); + + return IterateNullable (source, selector, (a, b) => a > b); + } + + public static float? Max (this IEnumerable source, Func selector) + { + Check.SourceAndSelector (source, selector); + + return IterateNullable (source, selector, (a, b) => a > b); + } + + public static decimal? Max (this IEnumerable source, Func selector) + { + Check.SourceAndSelector (source, selector); + + return IterateNullable (source, selector, (a, b) => a > b); + } + + public static TResult Max (this IEnumerable source, Func selector) + { + Check.SourceAndSelector (source, selector); + + bool notAssigned = true; + TResult maximum = default (TResult); + int counter = 0; + foreach (TSource item in source) { + TResult element = selector (item); + if (notAssigned) { + maximum = element; + notAssigned = false; + } else { + int comparison; + if (element is IComparable) + comparison = ((IComparable) element).CompareTo (maximum); + else if (element is System.IComparable) + comparison = ((System.IComparable) element).CompareTo (maximum); + else + throw new ArgumentNullException (); + + if (comparison > 0) + maximum = element; + } + counter++; + } + + if (counter == 0) + throw new InvalidOperationException (); + else + return maximum; + } + + #endregion + + #region Min + + public static int Min (this IEnumerable source) + { + Check.Source (source); + + return Iterate (source, int.MaxValue, (a, b) => Math.Min (a, b)); + } + + public static long Min (this IEnumerable source) + { + Check.Source (source); + + return Iterate (source, long.MaxValue, (a, b) => Math.Min (a, b)); + } + + public static double Min (this IEnumerable source) + { + Check.Source (source); + + return Iterate (source, double.MaxValue, (a, b) => Math.Min (a, b)); + } + + public static float Min (this IEnumerable source) + { + Check.Source (source); + + return Iterate (source, float.MaxValue, (a, b) => Math.Min (a, b)); + } + + public static decimal Min (this IEnumerable source) + { + Check.Source (source); + + return Iterate (source, decimal.MaxValue, (a, b) => Math.Min (a, b)); + } + + public static int? Min (this IEnumerable source) + { + Check.Source (source); + + return IterateNullable (source, (a, b) => Math.Min (a, b)); + } + + public static long? Min (this IEnumerable source) + { + Check.Source (source); + + return IterateNullable (source, (a, b) => Math.Min (a, b)); + } + + public static double? Min (this IEnumerable source) + { + Check.Source (source); + + return IterateNullable (source, (a, b) => Math.Min (a, b)); + } + + public static float? Min (this IEnumerable source) + { + Check.Source (source); + + return IterateNullable (source, (a, b) => Math.Min (a, b)); + } + + public static decimal? Min (this IEnumerable source) + { + Check.Source (source); + + return IterateNullable (source, (a, b) => Math.Min (a, b)); + } + + public static TSource Min (this IEnumerable source) + { + Check.Source (source); + + bool notAssigned = true; + TSource minimum = default (TSource); + int counter = 0; + foreach (TSource element in source) { + if (notAssigned) { + minimum = element; + notAssigned = false; + } else { + int comparison; + if (element is IComparable) + comparison = ((IComparable) element).CompareTo (minimum); + else if (element is System.IComparable) + comparison = ((System.IComparable) element).CompareTo (minimum); + else + throw new ArgumentNullException (); + + if (comparison < 0) + minimum = element; + } + counter++; + } + + if (counter == 0) + throw new InvalidOperationException (); + else + return minimum; + } + + public static int Min (this IEnumerable source, Func selector) + { + Check.SourceAndSelector (source, selector); + + return Iterate (source, int.MaxValue, (a, b) => Math.Min (selector (a), b)); + } + + public static long Min (this IEnumerable source, Func selector) + { + Check.SourceAndSelector (source, selector); + + return Iterate (source, long.MaxValue, (a, b) => Math.Min (selector (a), b)); + } + + public static double Min (this IEnumerable source, Func selector) + { + Check.SourceAndSelector (source, selector); + + return Iterate (source, double.MaxValue, (a, b) => Math.Min (selector (a), b)); + } + + public static float Min (this IEnumerable source, Func selector) + { + Check.SourceAndSelector (source, selector); + + return Iterate (source, float.MaxValue, (a, b) => Math.Min (selector (a), b)); + } + + public static decimal Min (this IEnumerable source, Func selector) + { + Check.SourceAndSelector (source, selector); + + return Iterate (source, decimal.MaxValue, (a, b) => Math.Min (selector (a), b)); + } + + public static int? Min (this IEnumerable source, Func selector) + { + Check.SourceAndSelector (source, selector); + + return IterateNullable (source, selector, (a, b) => a < b); + } + + public static long? Min (this IEnumerable source, Func selector) + { + Check.SourceAndSelector (source, selector); + + return IterateNullable (source, selector, (a, b) => a < b); + } + + public static float? Min (this IEnumerable source, Func selector) + { + Check.SourceAndSelector (source, selector); + + return IterateNullable (source, selector, (a, b) => a < b); + } + + public static double? Min (this IEnumerable source, Func selector) + { + Check.SourceAndSelector (source, selector); + + return IterateNullable (source, selector, (a, b) => a < b); + } + + public static decimal? Min (this IEnumerable source, Func selector) + { + Check.SourceAndSelector (source, selector); + + return IterateNullable (source, selector, (a, b) => a < b); + } + + public static TResult Min (this IEnumerable source, Func selector) + { + Check.SourceAndSelector (source, selector); + + bool notAssigned = true; + TResult minimum = default (TResult); + int counter = 0; + foreach (TSource item in source) { + TResult element = selector (item); + if (notAssigned) { + minimum = element; + notAssigned = false; + } else { + int comparison; + if (element is IComparable) + comparison = ((IComparable) element).CompareTo (minimum); + else if (element is System.IComparable) + comparison = ((System.IComparable) element).CompareTo (minimum); + else + throw new ArgumentNullException (); + + if (comparison < 0) + minimum = element; + } + counter++; + } + + if (counter == 0) + throw new InvalidOperationException (); + else + return minimum; + } + + #endregion + + #region OfType + + public static IEnumerable OfType (this IEnumerable source) + { + Check.Source (source); + + return CreateOfTypeIterator (source); + } + + static IEnumerable CreateOfTypeIterator (IEnumerable source) + { + foreach (object element in source) + if (element is TResult) + yield return (TResult) element; + } + + #endregion + + #region OrderBy + + public static IOrderedEnumerable OrderBy (this IEnumerable source, + Func keySelector) + { + return OrderBy (source, keySelector, null); + } + + public static IOrderedEnumerable OrderBy (this IEnumerable source, + Func keySelector, + IComparer comparer) + { + Check.SourceAndKeySelector (source, keySelector); + + return new OrderedSequence (source, keySelector, comparer, SortDirection.Ascending); + } + + #endregion + + #region OrderByDescending + + public static IOrderedEnumerable OrderByDescending (this IEnumerable source, + Func keySelector) + { + return OrderByDescending (source, keySelector, null); + } + + public static IOrderedEnumerable OrderByDescending (this IEnumerable source, + Func keySelector, IComparer comparer) + { + Check.SourceAndKeySelector (source, keySelector); + + return new OrderedSequence (source, keySelector, comparer, SortDirection.Descending); + } + + #endregion + + #region Range + + public static IEnumerable Range (int start, int count) + { + if (count < 0) + throw new ArgumentOutOfRangeException ("count"); + + long upto = ((long) start + count) - 1; + + if (upto > int.MaxValue) + throw new ArgumentOutOfRangeException (); + + return CreateRangeIterator (start, (int) upto); + } + + static IEnumerable CreateRangeIterator (int start, int upto) + { + for (int i = start; i <= upto; i++) + yield return i; + } + + #endregion + + #region Repeat + + public static IEnumerable Repeat (TResult element, int count) + { + if (count < 0) + throw new ArgumentOutOfRangeException (); + + return CreateRepeatIterator (element, count); + } + + static IEnumerable CreateRepeatIterator (TResult element, int count) + { + for (int i = 0; i < count; i++) + yield return element; + } + + #endregion + + #region Reverse + + public static IEnumerable Reverse (this IEnumerable source) + { + Check.Source (source); + + var list = source as IList; + if (list == null) + list = new List (source); + + return CreateReverseIterator (list); + } + + static IEnumerable CreateReverseIterator (IList source) + { + for (int i = source.Count; i > 0; --i) + yield return source [i - 1]; + } + + #endregion + + #region Select + + public static IEnumerable Select (this IEnumerable source, Func selector) + { + Check.SourceAndSelector (source, selector); + + return CreateSelectIterator (source, selector); + } + + static IEnumerable CreateSelectIterator (IEnumerable source, Func selector) + { + foreach (var element in source) + yield return selector (element); + } + + public static IEnumerable Select (this IEnumerable source, Func selector) + { + Check.SourceAndSelector (source, selector); + + return CreateSelectIterator (source, selector); + } + + static IEnumerable CreateSelectIterator (IEnumerable source, Func selector) + { + int counter = 0; + foreach (TSource element in source) { + yield return selector (element, counter); + counter++; + } + } + + #endregion + + #region SelectMany + + public static IEnumerable SelectMany (this IEnumerable source, Func> selector) + { + Check.SourceAndSelector (source, selector); + + return CreateSelectManyIterator (source, selector); + } + + static IEnumerable CreateSelectManyIterator (IEnumerable source, Func> selector) + { + foreach (TSource element in source) + foreach (TResult item in selector (element)) + yield return item; + } + + public static IEnumerable SelectMany (this IEnumerable source, Func> selector) + { + Check.SourceAndSelector (source, selector); + + return CreateSelectManyIterator (source, selector); + } + + static IEnumerable CreateSelectManyIterator (IEnumerable source, Func> selector) + { + int counter = 0; + foreach (TSource element in source) { + foreach (TResult item in selector (element, counter)) + yield return item; + counter++; + } + } + + public static IEnumerable SelectMany (this IEnumerable source, + Func> collectionSelector, Func selector) + { + Check.SourceAndCollectionSelectors (source, collectionSelector, selector); + + return CreateSelectManyIterator (source, collectionSelector, selector); + } + + static IEnumerable CreateSelectManyIterator (IEnumerable source, + Func> collectionSelector, Func selector) + { + foreach (TSource element in source) + foreach (TCollection collection in collectionSelector (element)) + yield return selector (element, collection); + } + + public static IEnumerable SelectMany (this IEnumerable source, + Func> collectionSelector, Func selector) + { + Check.SourceAndCollectionSelectors (source, collectionSelector, selector); + + return CreateSelectManyIterator (source, collectionSelector, selector); + } + + static IEnumerable CreateSelectManyIterator (IEnumerable source, + Func> collectionSelector, Func selector) + { + int counter = 0; + foreach (TSource element in source) + foreach (TCollection collection in collectionSelector (element, counter++)) + yield return selector (element, collection); + } + + #endregion + + #region Single + + static TSource Single (this IEnumerable source, Func predicate, Fallback fallback) + { + var found = false; + var item = default (TSource); + + foreach (var element in source) { + if (!predicate (element)) + continue; + + if (found) + throw new InvalidOperationException (); + + found = true; + item = element; + } + + if (!found && fallback == Fallback.Throw) + throw new InvalidOperationException (); + + return item; + } + + public static TSource Single (this IEnumerable source) + { + Check.Source (source); + + return source.Single (PredicateOf.Always, Fallback.Throw); + } + + public static TSource Single (this IEnumerable source, Func predicate) + { + Check.SourceAndPredicate (source, predicate); + + return source.Single (predicate, Fallback.Throw); + } + + #endregion + + #region SingleOrDefault + + public static TSource SingleOrDefault (this IEnumerable source) + { + Check.Source (source); + + return source.Single (PredicateOf.Always, Fallback.Default); + } + + public static TSource SingleOrDefault (this IEnumerable source, Func predicate) + { + Check.SourceAndPredicate (source, predicate); + + return source.Single (predicate, Fallback.Default); + } + + #endregion + + #region Skip + + public static IEnumerable Skip (this IEnumerable source, int count) + { + Check.Source (source); + + return CreateSkipIterator (source, count); + } + + static IEnumerable CreateSkipIterator (IEnumerable source, int count) + { + int i = 0; + foreach (var element in source) { + if (i++ < count) + continue; + + yield return element; + } + } + + #endregion + + #region SkipWhile + + public static IEnumerable SkipWhile (this IEnumerable source, Func predicate) + { + Check.SourceAndPredicate (source, predicate); + + return CreateSkipWhileIterator (source, predicate); + } + + static IEnumerable CreateSkipWhileIterator (IEnumerable source, Func predicate) + { + bool yield = false; + + foreach (TSource element in source) { + if (yield) + yield return element; + else + if (!predicate (element)) { + yield return element; + yield = true; + } + } + } + + public static IEnumerable SkipWhile (this IEnumerable source, Func predicate) + { + Check.SourceAndPredicate (source, predicate); + + return CreateSkipWhileIterator (source, predicate); + } + + static IEnumerable CreateSkipWhileIterator (IEnumerable source, Func predicate) + { + int counter = 0; + bool yield = false; + + foreach (TSource element in source) { + if (yield) + yield return element; + else + if (!predicate (element, counter)) { + yield return element; + yield = true; + } + counter++; + } + } + + #endregion + + #region Sum + + public static int Sum (this IEnumerable source) + { + Check.Source (source); + + return Sum (source, (a, b) => checked (a + b)); + } + + public static int? Sum (this IEnumerable source) + { + Check.Source (source); + + return source.SumNullable (0, (total, element) => element.HasValue ? checked (total + element) : total); + } + + public static int Sum (this IEnumerable source, Func selector) + { + Check.SourceAndSelector (source, selector); + + return Sum (source, (a, b) => checked (a + selector (b))); + } + + public static int? Sum (this IEnumerable source, Func selector) + { + Check.SourceAndSelector (source, selector); + + return source.SumNullable (0, (a, b) => { + var value = selector (b); + return value.HasValue ? checked (a + value.Value) : a; + }); + } + + public static long Sum (this IEnumerable source) + { + Check.Source (source); + + return Sum (source, (a, b) => checked (a + b)); + } + + public static long? Sum (this IEnumerable source) + { + Check.Source (source); + + return source.SumNullable (0, (total, element) => element.HasValue ? checked (total + element) : total); + } + + public static long Sum (this IEnumerable source, Func selector) + { + Check.SourceAndSelector (source, selector); + + return Sum (source, (a, b) => checked (a + selector (b))); + } + + public static long? Sum (this IEnumerable source, Func selector) + { + Check.SourceAndSelector (source, selector); + + return source.SumNullable (0, (a, b) => { + var value = selector (b); + return value.HasValue ? checked (a + value.Value) : a; + }); + } + + public static double Sum (this IEnumerable source) + { + Check.Source (source); + + return Sum (source, (a, b) => checked (a + b)); + } + + public static double? Sum (this IEnumerable source) + { + Check.Source (source); + + return source.SumNullable (0, (total, element) => element.HasValue ? checked (total + element) : total); + } + + public static double Sum (this IEnumerable source, Func selector) + { + Check.SourceAndSelector (source, selector); + + return Sum (source, (a, b) => checked (a + selector (b))); + } + + public static double? Sum (this IEnumerable source, Func selector) + { + Check.SourceAndSelector (source, selector); + + return source.SumNullable (0, (a, b) => { + var value = selector (b); + return value.HasValue ? checked (a + value.Value) : a; + }); + } + + public static float Sum (this IEnumerable source) + { + Check.Source (source); + + return Sum (source, (a, b) => checked (a + b)); + } + + public static float? Sum (this IEnumerable source) + { + Check.Source (source); + + return source.SumNullable (0, (total, element) => element.HasValue ? checked (total + element) : total); + } + + public static float Sum (this IEnumerable source, Func selector) + { + Check.SourceAndSelector (source, selector); + + return Sum (source, (a, b) => checked (a + selector (b))); + } + + public static float? Sum (this IEnumerable source, Func selector) + { + Check.SourceAndSelector (source, selector); + + return source.SumNullable (0, (a, b) => { + var value = selector (b); + return value.HasValue ? checked (a + value.Value) : a; + }); + } + + public static decimal Sum (this IEnumerable source) + { + Check.Source (source); + + return Sum (source, (a, b) => checked (a + b)); + } + + public static decimal? Sum (this IEnumerable source) + { + Check.Source (source); + + return source.SumNullable (0, (total, element) => element.HasValue ? checked (total + element) : total); + } + + public static decimal Sum (this IEnumerable source, Func selector) + { + Check.SourceAndSelector (source, selector); + + return Sum (source, (a, b) => checked (a + selector (b))); + } + + public static decimal? Sum (this IEnumerable source, Func selector) + { + Check.SourceAndSelector (source, selector); + + return source.SumNullable (0, (a, b) => { + var value = selector (b); + return value.HasValue ? checked (a + value.Value) : a; + }); + } + + static TR Sum (this IEnumerable source, Func selector) + { + TR total = default (TR); + long counter = 0; + foreach (var element in source) { + total = selector (total, element); + ++counter; + } + + return total; + } + + static TR SumNullable (this IEnumerable source, TR zero, Func selector) + { + TR total = zero; + foreach (var element in source) { + total = selector (total, element); + } + + return total; + } + + #endregion + + #region Take + + public static IEnumerable Take (this IEnumerable source, int count) + { + Check.Source (source); + + return CreateTakeIterator (source, count); + } + + static IEnumerable CreateTakeIterator (IEnumerable source, int count) + { + if (count <= 0) + yield break; + + int counter = 0; + foreach (TSource element in source) { + yield return element; + + if (++counter == count) + yield break; + } + } + + #endregion + + #region TakeWhile + + public static IEnumerable TakeWhile (this IEnumerable source, Func predicate) + { + Check.SourceAndPredicate (source, predicate); + + return CreateTakeWhileIterator (source, predicate); + } + + static IEnumerable CreateTakeWhileIterator (IEnumerable source, Func predicate) + { + foreach (var element in source) { + if (!predicate (element)) + yield break; + + yield return element; + } + } + + public static IEnumerable TakeWhile (this IEnumerable source, Func predicate) + { + Check.SourceAndPredicate (source, predicate); + + return CreateTakeWhileIterator (source, predicate); + } + + static IEnumerable CreateTakeWhileIterator (IEnumerable source, Func predicate) + { + int counter = 0; + foreach (var element in source) { + if (!predicate (element, counter)) + yield break; + + yield return element; + counter++; + } + } + + #endregion + + #region ThenBy + + public static IOrderedEnumerable ThenBy (this IOrderedEnumerable source, Func keySelector) + { + return ThenBy (source, keySelector, null); + } + + public static IOrderedEnumerable ThenBy (this IOrderedEnumerable source, + Func keySelector, IComparer comparer) + { + Check.SourceAndKeySelector (source, keySelector); + + return source.CreateOrderedEnumerable (keySelector, comparer, false); + } + + #endregion + + #region ThenByDescending + + public static IOrderedEnumerable ThenByDescending (this IOrderedEnumerable source, + Func keySelector) + { + return ThenByDescending (source, keySelector, null); + } + + public static IOrderedEnumerable ThenByDescending (this IOrderedEnumerable source, + Func keySelector, IComparer comparer) + { + Check.SourceAndKeySelector (source, keySelector); + + return source.CreateOrderedEnumerable (keySelector, comparer, true); + } + + #endregion + + #region ToArray + + public static TSource [] ToArray (this IEnumerable source) + { + Check.Source (source); + + var collection = source as ICollection; + if (collection != null) { + var array = new TSource [collection.Count]; + collection.CopyTo (array, 0); + return array; + } + + return new List (source).ToArray (); + } + + #endregion + + #region ToDictionary + public static Dictionary ToDictionary (this IEnumerable source, + Func keySelector, Func elementSelector) + { + return ToDictionary (source, keySelector, elementSelector, null); + } + + public static Dictionary ToDictionary (this IEnumerable source, + Func keySelector, Func elementSelector, IEqualityComparer comparer) + { + Check.SourceAndKeyElementSelectors (source, keySelector, elementSelector); + + if (comparer == null) + comparer = EqualityComparer.Default; + + var dict = new Dictionary (comparer); + foreach (var e in source) + dict.Add (keySelector (e), elementSelector (e)); + + return dict; + } + + public static Dictionary ToDictionary (this IEnumerable source, + Func keySelector) + { + return ToDictionary (source, keySelector, null); + } + + public static Dictionary ToDictionary (this IEnumerable source, + Func keySelector, IEqualityComparer comparer) + { + return ToDictionary (source, keySelector, Function.Identity, comparer); + } + + #endregion + + #region ToList + public static List ToList (this IEnumerable source) + { + Check.Source (source); + + return new List (source); + } + #endregion + + #region ToLookup + + public static ILookup ToLookup (this IEnumerable source, Func keySelector) + { + return ToLookup (source, keySelector, Function.Identity, null); + } + + public static ILookup ToLookup (this IEnumerable source, + Func keySelector, IEqualityComparer comparer) + { + return ToLookup (source, keySelector, element => element, comparer); + } + + public static ILookup ToLookup (this IEnumerable source, + Func keySelector, Func elementSelector) + { + return ToLookup (source, keySelector, elementSelector, null); + } + + public static ILookup ToLookup (this IEnumerable source, + Func keySelector, Func elementSelector, IEqualityComparer comparer) + { + Check.SourceAndKeyElementSelectors (source, keySelector, elementSelector); + + var dictionary = new Dictionary> (comparer ?? EqualityComparer.Default); + foreach (var element in source) { + var key = keySelector (element); + if (key == null) + throw new ArgumentNullException ("key"); + + List list; + if (!dictionary.TryGetValue (key, out list)) { + list = new List (); + dictionary.Add (key, list); + } + + list.Add (elementSelector (element)); + } + + return new Lookup (dictionary); + } + + #endregion + + #region SequenceEqual + + public static bool SequenceEqual (this IEnumerable first, IEnumerable second) + { + return first.SequenceEqual (second, null); + } + + public static bool SequenceEqual (this IEnumerable first, IEnumerable second, IEqualityComparer comparer) + { + Check.FirstAndSecond (first, second); + + if (comparer == null) + comparer = EqualityComparer.Default; + + using (IEnumerator first_enumerator = first.GetEnumerator (), + second_enumerator = second.GetEnumerator ()) { + + while (first_enumerator.MoveNext ()) { + if (!second_enumerator.MoveNext ()) + return false; + + if (!comparer.Equals (first_enumerator.Current, second_enumerator.Current)) + return false; + } + + return !second_enumerator.MoveNext (); + } + } + + #endregion + + #region Union + + public static IEnumerable Union (this IEnumerable first, IEnumerable second) + { + Check.FirstAndSecond (first, second); + + return first.Union (second, null); + } + + public static IEnumerable Union (this IEnumerable first, IEnumerable second, IEqualityComparer comparer) + { + Check.FirstAndSecond (first, second); + + if (comparer == null) + comparer = EqualityComparer.Default; + + return CreateUnionIterator (first, second, comparer); + } + + static IEnumerable CreateUnionIterator (IEnumerable first, IEnumerable second, IEqualityComparer comparer) + { + var items = new HashSet (comparer); + foreach (var element in first) { + if (! items.Contains (element)) { + items.Add (element); + yield return element; + } + } + + foreach (var element in second) { + if (! items.Contains (element, comparer)) { + items.Add (element); + yield return element; + } + } + } + + #endregion + + #region Where + + public static IEnumerable Where (this IEnumerable source, Func predicate) + { + Check.SourceAndPredicate (source, predicate); + + return CreateWhereIterator (source, predicate); + } + + static IEnumerable CreateWhereIterator (IEnumerable source, Func predicate) + { + foreach (TSource element in source) + if (predicate (element)) + yield return element; + } + + public static IEnumerable Where (this IEnumerable source, Func predicate) + { + Check.SourceAndPredicate (source, predicate); + + return CreateWhereIterator (source, predicate); + } + + static IEnumerable CreateWhereIterator (this IEnumerable source, Func predicate) + { + int counter = 0; + foreach (TSource element in source) { + if (predicate (element, counter)) + yield return element; + counter++; + } + } + + #endregion + + class ReadOnlyCollectionOf { + public static readonly ReadOnlyCollection Empty = new ReadOnlyCollection (new T [0]); + } + + internal static ReadOnlyCollection ToReadOnlyCollection (this IEnumerable source) + { + if (source == null) + return ReadOnlyCollectionOf.Empty; + + var ro = source as ReadOnlyCollection; + if (ro != null) + return ro; + + return new ReadOnlyCollection (source.ToArray ()); + } + } }