// 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) throw new ArgumentNullException ("source"); if (func == null) throw new ArgumentNullException ("func"); // custom foreach so that we can efficiently throw an exception // if zero elements and treat the first element differently using (IEnumerator 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) { 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 (TResult) 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) { return DefaultIfEmpty (source, default (TSource)); } public static IEnumerable DefaultIfEmpty (this IEnumerable source, TSource defaultValue) { if (source == null) throw new ArgumentNullException ("source"); 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 TSource FirstOrDefault (this IEnumerable source) { if (source == null) throw new ArgumentNullException (); foreach (TSource element in source) return element; return default (TSource); } public static TSource FirstOrDefault (this IEnumerable source, Func predicate) { if (source == null || predicate == null) throw new ArgumentNullException (); foreach (TSource element in source) { if (predicate (element)) return element; } return default (TSource); } #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, null); } 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]); else yield return resultSelector (element, Empty ()); } } #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, null); } # 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 TSource Max (this IEnumerable source) { if (source == null) throw new ArgumentNullException (); 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) { if (source == null || selector == null) throw new ArgumentNullException (); int maximum = int.MinValue; int counter = 0; foreach (TSource 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 (TSource 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 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) { if (source == null || keySelector == null) throw new ArgumentNullException (); return new InternalOrderedSequence ( source, keySelector, comparer, false); } #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) { if (source == null || keySelector == null) throw new ArgumentNullException (); return new InternalOrderedSequence ( source, keySelector, comparer, true); } #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++; } } public static IEnumerable SelectMany (this IEnumerable source, Func> collectionSelector, Func selector) { if (source == null || collectionSelector == null || selector == null) throw new ArgumentNullException (); 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) { if (source == null || collectionSelector == null || selector == null) throw new ArgumentNullException (); int counter = 0; foreach (TSource element in source) foreach (TCollection collection in collectionSelector (element, counter++)) yield return selector (element, collection); } #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 ( this IEnumerable source, Func predicate) { if (source == null || predicate == null) throw new ArgumentNullException (); 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) { 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 (TSource 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 (TSource 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 IOrderedEnumerable ThenBy (this IOrderedEnumerable source, Func keySelector) { return ThenBy (source, keySelector, null); } public static IOrderedEnumerable ThenBy (this IOrderedEnumerable source, Func keySelector, IComparer comparer) { if (source == null || keySelector == null) throw new ArgumentNullException (); 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) { if (source == null || keySelector == null) throw new ArgumentNullException (); return source.CreateOrderedEnumerable (keySelector, comparer, true); } #endregion #region ToArray public static TSource [] 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 (TSource element in first) { if (IndexOf (items, element) == -1) { items.Add (element); yield return element; } } foreach (TSource 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 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; } 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 } }