#if !HAVE_LINQ #region License, Terms and Author(s) // // LINQBridge // Copyright (c) 2007-9 Atif Aziz, Joseph Albahari. All rights reserved. // // Author(s): // // Atif Aziz, http://www.raboof.com // // This library is free software; you can redistribute it and/or modify it // under the terms of the New BSD License, a copy of which should have // been delivered along with this distribution. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A // PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // #endregion using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using LC.Newtonsoft.Json.Serialization; namespace LC.Newtonsoft.Json.Utilities.LinqBridge { /// /// Provides a set of static (Shared in Visual Basic) methods for /// querying objects that implement . /// internal static partial class Enumerable { /// /// Returns the input typed as . /// public static IEnumerable AsEnumerable(IEnumerable source) { return source; } /// /// Returns an empty that has the /// specified type argument. /// public static IEnumerable Empty() { return Sequence.Empty; } /// /// Converts the elements of an to the /// specified type. /// public static IEnumerable Cast( this IEnumerable source) { CheckNotNull(source, "source"); var servesItself = source as IEnumerable; if (servesItself != null && (!(servesItself is TResult[]) || servesItself.GetType().GetElementType() == typeof(TResult))) { return servesItself; } return CastYield(source); } private static IEnumerable CastYield( IEnumerable source) { foreach (var item in source) yield return (TResult) item; } /// /// Filters the elements of an based on a specified type. /// public static IEnumerable OfType( this IEnumerable source) { CheckNotNull(source, "source"); return OfTypeYield(source); } private static IEnumerable OfTypeYield( IEnumerable source) { foreach (var item in source) if (item is TResult) yield return (TResult) item; } /// /// Generates a sequence of integral numbers within a specified range. /// /// The value of the first integer in the sequence. /// The number of sequential integers to generate. public static IEnumerable Range(int start, int count) { if (count < 0) throw new ArgumentOutOfRangeException("count", count, null); var end = (long) start + count; if (end - 1 >= int.MaxValue) throw new ArgumentOutOfRangeException("count", count, null); return RangeYield(start, end); } private static IEnumerable RangeYield(int start, long end) { for (var i = start; i < end; i++) yield return i; } /// /// Generates a sequence that contains one repeated value. /// public static IEnumerable Repeat(TResult element, int count) { if (count < 0) throw new ArgumentOutOfRangeException("count", count, null); return RepeatYield(element, count); } private static IEnumerable RepeatYield(TResult element, int count) { for (var i = 0; i < count; i++) yield return element; } /// /// Filters a sequence of values based on a predicate. /// public static IEnumerable Where( this IEnumerable source, Func predicate) { CheckNotNull(source, "source"); CheckNotNull(predicate, "predicate"); return WhereYield(source, predicate); } private static IEnumerable WhereYield( IEnumerable source, Func predicate) { foreach (var item in source) if (predicate(item)) yield return item; } /// /// Filters a sequence of values based on a predicate. /// Each element's index is used in the logic of the predicate function. /// public static IEnumerable Where( this IEnumerable source, Func predicate) { CheckNotNull(source, "source"); CheckNotNull(predicate, "predicate"); return WhereYield(source, predicate); } private static IEnumerable WhereYield( IEnumerable source, Func predicate) { var i = 0; foreach (var item in source) if (predicate(item, i++)) yield return item; } /// /// Projects each element of a sequence into a new form. /// public static IEnumerable Select( this IEnumerable source, Func selector) { CheckNotNull(source, "source"); CheckNotNull(selector, "selector"); return SelectYield(source, selector); } private static IEnumerable SelectYield( IEnumerable source, Func selector) { foreach (var item in source) yield return selector(item); } /// /// Projects each element of a sequence into a new form by /// incorporating the element's index. /// public static IEnumerable Select( this IEnumerable source, Func selector) { CheckNotNull(source, "source"); CheckNotNull(selector, "selector"); return SelectYield(source, selector); } private static IEnumerable SelectYield( IEnumerable source, Func selector) { var i = 0; foreach (var item in source) yield return selector(item, i++); } /// /// Projects each element of a sequence to an /// and flattens the resulting sequences into one sequence. /// public static IEnumerable SelectMany( this IEnumerable source, Func> selector) { CheckNotNull(selector, "selector"); return source.SelectMany((item, i) => selector(item)); } /// /// Projects each element of a sequence to an , /// and flattens the resulting sequences into one sequence. The /// index of each source element is used in the projected form of /// that element. /// public static IEnumerable SelectMany( this IEnumerable source, Func> selector) { CheckNotNull(selector, "selector"); return source.SelectMany(selector, (item, subitem) => subitem); } /// /// Projects each element of a sequence to an , /// flattens the resulting sequences into one sequence, and invokes /// a result selector function on each element therein. /// public static IEnumerable SelectMany( this IEnumerable source, Func> collectionSelector, Func resultSelector) { CheckNotNull(collectionSelector, "collectionSelector"); return source.SelectMany((item, i) => collectionSelector(item), resultSelector); } /// /// Projects each element of a sequence to an , /// flattens the resulting sequences into one sequence, and invokes /// a result selector function on each element therein. The index of /// each source element is used in the intermediate projected form /// of that element. /// public static IEnumerable SelectMany( this IEnumerable source, Func> collectionSelector, Func resultSelector) { CheckNotNull(source, "source"); CheckNotNull(collectionSelector, "collectionSelector"); CheckNotNull(resultSelector, "resultSelector"); return SelectManyYield(source, collectionSelector, resultSelector); } private static IEnumerable SelectManyYield( this IEnumerable source, Func> collectionSelector, Func resultSelector) { var i = 0; foreach (var item in source) foreach (var subitem in collectionSelector(item, i++)) yield return resultSelector(item, subitem); } /// /// Returns elements from a sequence as long as a specified condition is true. /// public static IEnumerable TakeWhile( this IEnumerable source, Func predicate) { CheckNotNull(predicate, "predicate"); return source.TakeWhile((item, i) => predicate(item)); } /// /// Returns elements from a sequence as long as a specified condition is true. /// The element's index is used in the logic of the predicate function. /// public static IEnumerable TakeWhile( this IEnumerable source, Func predicate) { CheckNotNull(source, "source"); CheckNotNull(predicate, "predicate"); return TakeWhileYield(source, predicate); } private static IEnumerable TakeWhileYield( this IEnumerable source, Func predicate) { var i = 0; foreach (var item in source) if (predicate(item, i++)) yield return item; else break; } private static class Futures { public static readonly Func Default = () => default(T); public static readonly Func Undefined = () => { throw new InvalidOperationException(); }; } /// /// Base implementation of First operator. /// private static TSource FirstImpl( this IEnumerable source, Func empty) { CheckNotNull(source, "source"); Debug.Assert(empty != null); var list = source as IList; // optimized case for lists if (list != null) return list.Count > 0 ? list[0] : empty(); using (var e = source.GetEnumerator()) // fallback for enumeration return e.MoveNext() ? e.Current : empty(); } /// /// Returns the first element of a sequence. /// public static TSource First( this IEnumerable source) { return source.FirstImpl(Futures.Undefined); } /// /// Returns the first element in a sequence that satisfies a specified condition. /// public static TSource First( this IEnumerable source, Func predicate) { return First(source.Where(predicate)); } /// /// Returns the first element of a sequence, or a default value if /// the sequence contains no elements. /// public static TSource FirstOrDefault( this IEnumerable source) { return source.FirstImpl(Futures.Default); } /// /// Returns the first element of the sequence that satisfies a /// condition or a default value if no such element is found. /// public static TSource FirstOrDefault( this IEnumerable source, Func predicate) { return FirstOrDefault(source.Where(predicate)); } /// /// Base implementation of Last operator. /// private static TSource LastImpl( this IEnumerable source, Func empty) { CheckNotNull(source, "source"); var list = source as IList; // optimized case for lists if (list != null) return list.Count > 0 ? list[list.Count - 1] : empty(); using (var e = source.GetEnumerator()) { if (!e.MoveNext()) return empty(); var last = e.Current; while (e.MoveNext()) last = e.Current; return last; } } /// /// Returns the last element of a sequence. /// public static TSource Last( this IEnumerable source) { return source.LastImpl(Futures.Undefined); } /// /// Returns the last element of a sequence that satisfies a /// specified condition. /// public static TSource Last( this IEnumerable source, Func predicate) { return Last(source.Where(predicate)); } /// /// Returns the last element of a sequence, or a default value if /// the sequence contains no elements. /// public static TSource LastOrDefault( this IEnumerable source) { return source.LastImpl(Futures.Default); } /// /// Returns the last element of a sequence that satisfies a /// condition or a default value if no such element is found. /// public static TSource LastOrDefault( this IEnumerable source, Func predicate) { return LastOrDefault(source.Where(predicate)); } /// /// Base implementation of Single operator. /// private static TSource SingleImpl( this IEnumerable source, Func empty) { CheckNotNull(source, "source"); using (var e = source.GetEnumerator()) { if (e.MoveNext()) { var single = e.Current; if (!e.MoveNext()) return single; throw new InvalidOperationException(); } return empty(); } } /// /// Returns the only element of a sequence, and throws an exception /// if there is not exactly one element in the sequence. /// public static TSource Single( this IEnumerable source) { return source.SingleImpl(Futures.Undefined); } /// /// Returns the only element of a sequence that satisfies a /// specified condition, and throws an exception if more than one /// such element exists. /// public static TSource Single( this IEnumerable source, Func predicate) { return Single(source.Where(predicate)); } /// /// Returns the only element of a sequence, or a default value if /// the sequence is empty; this method throws an exception if there /// is more than one element in the sequence. /// public static TSource SingleOrDefault( this IEnumerable source) { return source.SingleImpl(Futures.Default); } /// /// Returns the only element of a sequence that satisfies a /// specified condition or a default value if no such element /// exists; this method throws an exception if more than one element /// satisfies the condition. /// public static TSource SingleOrDefault( this IEnumerable source, Func predicate) { return SingleOrDefault(source.Where(predicate)); } /// /// Returns the element at a specified index in a sequence. /// public static TSource ElementAt( this IEnumerable source, int index) { CheckNotNull(source, "source"); if (index < 0) throw new ArgumentOutOfRangeException("index", index, null); var list = source as IList; if (list != null) return list[index]; try { return source.SkipWhile((item, i) => i < index).First(); } catch (InvalidOperationException) // if thrown by First { throw new ArgumentOutOfRangeException("index", index, null); } } /// /// Returns the element at a specified index in a sequence or a /// default value if the index is out of range. /// public static TSource ElementAtOrDefault( this IEnumerable source, int index) { CheckNotNull(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.SkipWhile((item, i) => i < index).FirstOrDefault(); } /// /// Inverts the order of the elements in a sequence. /// public static IEnumerable Reverse( this IEnumerable source) { CheckNotNull(source, "source"); return ReverseYield(source); } private static IEnumerable ReverseYield(IEnumerable source) { var stack = new Stack(source); foreach (var item in stack) yield return item; } /// /// Returns a specified number of contiguous elements from the start /// of a sequence. /// public static IEnumerable Take( this IEnumerable source, int count) { return source.Where((item, i) => i < count); } /// /// Bypasses a specified number of elements in a sequence and then /// returns the remaining elements. /// public static IEnumerable Skip( this IEnumerable source, int count) { return source.Where((item, i) => i >= count); } /// /// Bypasses elements in a sequence as long as a specified condition /// is true and then returns the remaining elements. /// public static IEnumerable SkipWhile( this IEnumerable source, Func predicate) { CheckNotNull(predicate, "predicate"); return source.SkipWhile((item, i) => predicate(item)); } /// /// Bypasses elements in a sequence as long as a specified condition /// is true and then returns the remaining elements. The element's /// index is used in the logic of the predicate function. /// public static IEnumerable SkipWhile( this IEnumerable source, Func predicate) { CheckNotNull(source, "source"); CheckNotNull(predicate, "predicate"); return SkipWhileYield(source, predicate); } private static IEnumerable SkipWhileYield( IEnumerable source, Func predicate) { using (var e = source.GetEnumerator()) { for (var i = 0;; i++) { if (!e.MoveNext()) yield break; if (!predicate(e.Current, i)) break; } do { yield return e.Current; } while (e.MoveNext()); } } /// /// Returns the number of elements in a sequence. /// public static int Count( this IEnumerable source) { CheckNotNull(source, "source"); var collection = source as ICollection; if (collection != null) { return collection.Count; } using (var en = source.GetEnumerator()) { int count = 0; while (en.MoveNext()) { ++count; } return count; } } /// /// Returns a number that represents how many elements in the /// specified sequence satisfy a condition. /// public static int Count( this IEnumerable source, Func predicate) { return Count(source.Where(predicate)); } /// /// Returns a that represents the total number /// of elements in a sequence. /// public static long LongCount( this IEnumerable source) { CheckNotNull(source, "source"); var array = source as Array; return array != null ? array.LongLength : source.Aggregate(0L, (count, item) => count + 1); } /// /// Returns a that represents how many elements /// in a sequence satisfy a condition. /// public static long LongCount( this IEnumerable source, Func predicate) { return LongCount(source.Where(predicate)); } /// /// Concatenates two sequences. /// public static IEnumerable Concat( this IEnumerable first, IEnumerable second) { CheckNotNull(first, "first"); CheckNotNull(second, "second"); return ConcatYield(first, second); } private static IEnumerable ConcatYield( IEnumerable first, IEnumerable second) { foreach (var item in first) yield return item; foreach (var item in second) yield return item; } /// /// Creates a from an . /// public static List ToList( this IEnumerable source) { CheckNotNull(source, "source"); return new List(source); } /// /// Creates an array from an . /// public static TSource[] ToArray( this IEnumerable source) { IList ilist = source as IList; if (ilist != null) { TSource[] array = new TSource[ilist.Count]; ilist.CopyTo(array, 0); return array; } return source.ToList().ToArray(); } /// /// Returns distinct elements from a sequence by using the default /// equality comparer to compare values. /// public static IEnumerable Distinct( this IEnumerable source) { return Distinct(source, /* comparer */ null); } /// /// Returns distinct elements from a sequence by using a specified /// to compare values. /// public static IEnumerable Distinct( this IEnumerable source, IEqualityComparer comparer) { CheckNotNull(source, "source"); return DistinctYield(source, comparer); } private static IEnumerable DistinctYield( IEnumerable source, IEqualityComparer comparer) { var set = new Dictionary(comparer); var gotNull = false; foreach (var item in source) { if (item == null) { if (gotNull) continue; gotNull = true; } else { if (set.ContainsKey(item)) continue; set.Add(item, null); } yield return item; } } /// /// Creates a from an /// according to a specified key /// selector function. /// public static ILookup ToLookup( this IEnumerable source, Func keySelector) { return ToLookup(source, keySelector, e => e, /* comparer */ null); } /// /// Creates a from an /// according to a specified key /// selector function and a key comparer. /// public static ILookup ToLookup( this IEnumerable source, Func keySelector, IEqualityComparer comparer) { return ToLookup(source, keySelector, e => e, comparer); } /// /// Creates a from an /// according to specified key /// and element selector functions. /// public static ILookup ToLookup( this IEnumerable source, Func keySelector, Func elementSelector) { return ToLookup(source, keySelector, elementSelector, /* comparer */ null); } /// /// Creates a from an /// according to a specified key /// selector function, a comparer and an element selector function. /// public static ILookup ToLookup( this IEnumerable source, Func keySelector, Func elementSelector, IEqualityComparer comparer) { CheckNotNull(source, "source"); CheckNotNull(keySelector, "keySelector"); CheckNotNull(elementSelector, "elementSelector"); var lookup = new Lookup(comparer); foreach (var item in source) { var key = keySelector(item); var grouping = (Grouping) lookup.Find(key); if (grouping == null) { grouping = new Grouping(key); lookup.Add(grouping); } grouping.Add(elementSelector(item)); } return lookup; } /// /// Groups the elements of a sequence according to a specified key /// selector function. /// public static IEnumerable> GroupBy( this IEnumerable source, Func keySelector) { return GroupBy(source, keySelector, /* comparer */ null); } /// /// Groups the elements of a sequence according to a specified key /// selector function and compares the keys by using a specified /// comparer. /// public static IEnumerable> GroupBy( this IEnumerable source, Func keySelector, IEqualityComparer comparer) { return GroupBy(source, keySelector, e => e, comparer); } /// /// Groups the elements of a sequence according to a specified key /// selector function and projects the elements for each group by /// using a specified function. /// public static IEnumerable> GroupBy( this IEnumerable source, Func keySelector, Func elementSelector) { return GroupBy(source, keySelector, elementSelector, /* comparer */ null); } /// /// Groups the elements of a sequence according to a specified key /// selector function and creates a result value from each group and /// its key. /// public static IEnumerable> GroupBy( this IEnumerable source, Func keySelector, Func elementSelector, IEqualityComparer comparer) { CheckNotNull(source, "source"); CheckNotNull(keySelector, "keySelector"); CheckNotNull(elementSelector, "elementSelector"); return ToLookup(source, keySelector, elementSelector, comparer); } /// /// Groups the elements of a sequence according to a key selector /// function. The keys are compared by using a comparer and each /// group's elements are projected by using a specified function. /// public static IEnumerable GroupBy( this IEnumerable source, Func keySelector, Func, TResult> resultSelector) { return GroupBy(source, keySelector, resultSelector, /* comparer */ null); } /// /// Groups the elements of a sequence according to a specified key /// selector function and creates a result value from each group and /// its key. The elements of each group are projected by using a /// specified function. /// public static IEnumerable GroupBy( this IEnumerable source, Func keySelector, Func, TResult> resultSelector, IEqualityComparer comparer) { CheckNotNull(source, "source"); CheckNotNull(keySelector, "keySelector"); CheckNotNull(resultSelector, "resultSelector"); return ToLookup(source, keySelector, comparer).Select(g => resultSelector(g.Key, g)); } /// /// Groups the elements of a sequence according to a specified key /// selector function and creates a result value from each group and /// its key. The keys are compared by using a specified comparer. /// public static IEnumerable GroupBy( this IEnumerable source, Func keySelector, Func elementSelector, Func, TResult> resultSelector) { return GroupBy(source, keySelector, elementSelector, resultSelector, /* comparer */ null); } /// /// Groups the elements of a sequence according to a specified key /// selector function and creates a result value from each group and /// its key. Key values are compared by using a specified comparer, /// and the elements of each group are projected by using a /// specified function. /// public static IEnumerable GroupBy( this IEnumerable source, Func keySelector, Func elementSelector, Func, TResult> resultSelector, IEqualityComparer comparer) { CheckNotNull(source, "source"); CheckNotNull(keySelector, "keySelector"); CheckNotNull(elementSelector, "elementSelector"); CheckNotNull(resultSelector, "resultSelector"); return ToLookup(source, keySelector, elementSelector, comparer) .Select(g => resultSelector(g.Key, g)); } /// /// Applies an accumulator function over a sequence. /// public static TSource Aggregate( this IEnumerable source, Func func) { CheckNotNull(source, "source"); CheckNotNull(func, "func"); using (var e = source.GetEnumerator()) { if (!e.MoveNext()) throw new InvalidOperationException(); return e.Renumerable().Skip(1).Aggregate(e.Current, func); } } /// /// Applies an accumulator function over a sequence. The specified /// seed value is used as the initial accumulator value. /// public static TAccumulate Aggregate( this IEnumerable source, TAccumulate seed, Func func) { return Aggregate(source, seed, func, r => r); } /// /// Applies an accumulator function over a sequence. The specified /// seed value is used as the initial accumulator value, and the /// specified function is used to select the result value. /// public static TResult Aggregate( this IEnumerable source, TAccumulate seed, Func func, Func resultSelector) { CheckNotNull(source, "source"); CheckNotNull(func, "func"); CheckNotNull(resultSelector, "resultSelector"); var result = seed; foreach (var item in source) result = func(result, item); return resultSelector(result); } /// /// Produces the set union of two sequences by using the default /// equality comparer. /// public static IEnumerable Union( this IEnumerable first, IEnumerable second) { return Union(first, second, /* comparer */ null); } /// /// Produces the set union of two sequences by using a specified /// . /// public static IEnumerable Union( this IEnumerable first, IEnumerable second, IEqualityComparer comparer) { return first.Concat(second).Distinct(comparer); } /// /// Returns the elements of the specified sequence or the type /// parameter's default value in a singleton collection if the /// sequence is empty. /// public static IEnumerable DefaultIfEmpty( this IEnumerable source) { return source.DefaultIfEmpty(default(TSource)); } /// /// Returns the elements of the specified sequence or the specified /// value in a singleton collection if the sequence is empty. /// public static IEnumerable DefaultIfEmpty( this IEnumerable source, TSource defaultValue) { CheckNotNull(source, "source"); return DefaultIfEmptyYield(source, defaultValue); } private static IEnumerable DefaultIfEmptyYield( IEnumerable source, TSource defaultValue) { using (var e = source.GetEnumerator()) { if (!e.MoveNext()) yield return defaultValue; else do { yield return e.Current; } while (e.MoveNext()); } } /// /// Determines whether all elements of a sequence satisfy a condition. /// public static bool All( this IEnumerable source, Func predicate) { CheckNotNull(source, "source"); CheckNotNull(predicate, "predicate"); foreach (var item in source) if (!predicate(item)) return false; return true; } /// /// Determines whether a sequence contains any elements. /// public static bool Any( this IEnumerable source) { CheckNotNull(source, "source"); using (var e = source.GetEnumerator()) return e.MoveNext(); } /// /// Determines whether any element of a sequence satisfies a /// condition. /// public static bool Any( this IEnumerable source, Func predicate) { foreach (TSource item in source) { if (predicate(item)) { return true; } } return false; } /// /// Determines whether a sequence contains a specified element by /// using the default equality comparer. /// public static bool Contains( this IEnumerable source, TSource value) { return source.Contains(value, /* comparer */ null); } /// /// Determines whether a sequence contains a specified element by /// using a specified . /// public static bool Contains( this IEnumerable source, TSource value, IEqualityComparer comparer) { CheckNotNull(source, "source"); if (comparer == null) { var collection = source as ICollection; if (collection != null) return collection.Contains(value); } comparer = comparer ?? EqualityComparer.Default; return source.Any(item => comparer.Equals(item, value)); } /// /// Determines whether two sequences are equal by comparing the /// elements by using the default equality comparer for their type. /// public static bool SequenceEqual( this IEnumerable first, IEnumerable second) { return first.SequenceEqual(second, /* comparer */ null); } /// /// Determines whether two sequences are equal by comparing their /// elements by using a specified . /// public static bool SequenceEqual( this IEnumerable first, IEnumerable second, IEqualityComparer comparer) { CheckNotNull(first, "first"); CheckNotNull(second, "second"); comparer = comparer ?? EqualityComparer.Default; using (IEnumerator lhs = first.GetEnumerator(), rhs = second.GetEnumerator()) { do { if (!lhs.MoveNext()) return !rhs.MoveNext(); if (!rhs.MoveNext()) return false; } while (comparer.Equals(lhs.Current, rhs.Current)); } return false; } /// /// Base implementation for Min/Max operator. /// private static TSource MinMaxImpl( this IEnumerable source, Func lesser) { CheckNotNull(source, "source"); Debug.Assert(lesser != null); return source.Aggregate((a, item) => lesser(a, item) ? a : item); } /// /// Base implementation for Min/Max operator for nullable types. /// private static TSource? MinMaxImpl( this IEnumerable source, TSource? seed, Func lesser) where TSource : struct { CheckNotNull(source, "source"); Debug.Assert(lesser != null); return source.Aggregate(seed, (a, item) => lesser(a, item) ? a : item); // == MinMaxImpl(Repeat(null, 1).Concat(source), lesser); } /// /// Returns the minimum value in a generic sequence. /// public static TSource Min( this IEnumerable source) { var comparer = Comparer.Default; return source.MinMaxImpl((x, y) => comparer.Compare(x, y) < 0); } /// /// Invokes a transform function on each element of a generic /// sequence and returns the minimum resulting value. /// public static TResult Min( this IEnumerable source, Func selector) { return source.Select(selector).Min(); } /// /// Returns the maximum value in a generic sequence. /// public static TSource Max( this IEnumerable source) { var comparer = Comparer.Default; return source.MinMaxImpl((x, y) => comparer.Compare(x, y) > 0); } /// /// Invokes a transform function on each element of a generic /// sequence and returns the maximum resulting value. /// public static TResult Max( this IEnumerable source, Func selector) { return source.Select(selector).Max(); } /// /// Makes an enumerator seen as enumerable once more. /// /// /// The supplied enumerator must have been started. The first element /// returned is the element the enumerator was on when passed in. /// DO NOT use this method if the caller must be a generator. It is /// mostly safe among aggregate operations. /// private static IEnumerable Renumerable(this IEnumerator e) { Debug.Assert(e != null); do { yield return e.Current; } while (e.MoveNext()); } /// /// Sorts the elements of a sequence in ascending order according to a key. /// public static IOrderedEnumerable OrderBy( this IEnumerable source, Func keySelector) { return source.OrderBy(keySelector, /* comparer */ null); } /// /// Sorts the elements of a sequence in ascending order by using a /// specified comparer. /// public static IOrderedEnumerable OrderBy( this IEnumerable source, Func keySelector, IComparer comparer) { CheckNotNull(source, "source"); CheckNotNull(keySelector, "keySelector"); return new OrderedEnumerable(source, keySelector, comparer, /* descending */ false); } /// /// Sorts the elements of a sequence in descending order according to a key. /// public static IOrderedEnumerable OrderByDescending( this IEnumerable source, Func keySelector) { return source.OrderByDescending(keySelector, /* comparer */ null); } /// /// Sorts the elements of a sequence in descending order by using a /// specified comparer. /// public static IOrderedEnumerable OrderByDescending( this IEnumerable source, Func keySelector, IComparer comparer) { CheckNotNull(source, "source"); CheckNotNull(source, "keySelector"); return new OrderedEnumerable(source, keySelector, comparer, /* descending */ true); } /// /// Performs a subsequent ordering of the elements in a sequence in /// ascending order according to a key. /// public static IOrderedEnumerable ThenBy( this IOrderedEnumerable source, Func keySelector) { return source.ThenBy(keySelector, /* comparer */ null); } /// /// Performs a subsequent ordering of the elements in a sequence in /// ascending order by using a specified comparer. /// public static IOrderedEnumerable ThenBy( this IOrderedEnumerable source, Func keySelector, IComparer comparer) { CheckNotNull(source, "source"); return source.CreateOrderedEnumerable(keySelector, comparer, /* descending */ false); } /// /// Performs a subsequent ordering of the elements in a sequence in /// descending order, according to a key. /// public static IOrderedEnumerable ThenByDescending( this IOrderedEnumerable source, Func keySelector) { return source.ThenByDescending(keySelector, /* comparer */ null); } /// /// Performs a subsequent ordering of the elements in a sequence in /// descending order by using a specified comparer. /// public static IOrderedEnumerable ThenByDescending( this IOrderedEnumerable source, Func keySelector, IComparer comparer) { CheckNotNull(source, "source"); return source.CreateOrderedEnumerable(keySelector, comparer, /* descending */ true); } /// /// Base implementation for Intersect and Except operators. /// private static IEnumerable IntersectExceptImpl( this IEnumerable first, IEnumerable second, IEqualityComparer comparer, bool flag) { CheckNotNull(first, "first"); CheckNotNull(second, "second"); var keys = new List(); var flags = new Dictionary(comparer); foreach (var item in first.Where(k => !flags.ContainsKey(k))) { flags.Add(item, !flag); keys.Add(item); } foreach (var item in second.Where(flags.ContainsKey)) flags[item] = flag; // // As per docs, "the marked elements are yielded in the order in // which they were collected. // return keys.Where(item => flags[item]); } /// /// Produces the set intersection of two sequences by using the /// default equality comparer to compare values. /// public static IEnumerable Intersect( this IEnumerable first, IEnumerable second) { return first.Intersect(second, /* comparer */ null); } /// /// Produces the set intersection of two sequences by using the /// specified to compare values. /// public static IEnumerable Intersect( this IEnumerable first, IEnumerable second, IEqualityComparer comparer) { return IntersectExceptImpl(first, second, comparer, /* flag */ true); } /// /// Produces the set difference of two sequences by using the /// default equality comparer to compare values. /// public static IEnumerable Except( this IEnumerable first, IEnumerable second) { return first.Except(second, /* comparer */ null); } /// /// Produces the set difference of two sequences by using the /// specified to compare values. /// public static IEnumerable Except( this IEnumerable first, IEnumerable second, IEqualityComparer comparer) { return IntersectExceptImpl(first, second, comparer, /* flag */ false); } /// /// Creates a from an /// according to a specified key /// selector function. /// public static Dictionary ToDictionary( this IEnumerable source, Func keySelector) { return source.ToDictionary(keySelector, /* comparer */ null); } /// /// Creates a from an /// according to a specified key /// selector function and key comparer. /// public static Dictionary ToDictionary( this IEnumerable source, Func keySelector, IEqualityComparer comparer) { return source.ToDictionary(keySelector, e => e); } /// /// Creates a from an /// according to specified key /// selector and element selector functions. /// public static Dictionary ToDictionary( this IEnumerable source, Func keySelector, Func elementSelector) { return source.ToDictionary(keySelector, elementSelector, /* comparer */ null); } /// /// Creates a from an /// according to a specified key /// selector function, a comparer, and an element selector function. /// public static Dictionary ToDictionary( this IEnumerable source, Func keySelector, Func elementSelector, IEqualityComparer comparer) { CheckNotNull(source, "source"); CheckNotNull(keySelector, "keySelector"); CheckNotNull(elementSelector, "elementSelector"); var dict = new Dictionary(comparer); foreach (var item in source) { // // ToDictionary is meant to throw ArgumentNullException if // keySelector produces a key that is null and // Argument exception if keySelector produces duplicate keys // for two elements. Incidentally, the documentation for // IDictionary.Add says that the Add method // throws the same exceptions under the same circumstances // so we don't need to do any additional checking or work // here and let the Add implementation do all the heavy // lifting. // dict.Add(keySelector(item), elementSelector(item)); } return dict; } /// /// Correlates the elements of two sequences based on matching keys. /// The default equality comparer is used to compare keys. /// public static IEnumerable Join( this IEnumerable outer, IEnumerable inner, Func outerKeySelector, Func innerKeySelector, Func resultSelector) { return outer.Join(inner, outerKeySelector, innerKeySelector, resultSelector, /* comparer */ null); } /// /// Correlates the elements of two sequences based on matching keys. /// The default equality comparer is used to compare keys. A /// specified is used to compare keys. /// public static IEnumerable Join( this IEnumerable outer, IEnumerable inner, Func outerKeySelector, Func innerKeySelector, Func resultSelector, IEqualityComparer comparer) { CheckNotNull(outer, "outer"); CheckNotNull(inner, "inner"); CheckNotNull(outerKeySelector, "outerKeySelector"); CheckNotNull(innerKeySelector, "innerKeySelector"); CheckNotNull(resultSelector, "resultSelector"); var lookup = inner.ToLookup(innerKeySelector, comparer); return from o in outer from i in lookup[outerKeySelector(o)] select resultSelector(o, i); } /// /// Correlates the elements of two sequences based on equality of /// keys and groups the results. The default equality comparer is /// used to compare keys. /// public static IEnumerable GroupJoin( this IEnumerable outer, IEnumerable inner, Func outerKeySelector, Func innerKeySelector, Func, TResult> resultSelector) { return outer.GroupJoin(inner, outerKeySelector, innerKeySelector, resultSelector, /* comparer */ null); } /// /// Correlates the elements of two sequences based on equality of /// keys and groups the results. The default equality comparer is /// used to compare keys. A specified /// is used to compare keys. /// public static IEnumerable GroupJoin( this IEnumerable outer, IEnumerable inner, Func outerKeySelector, Func innerKeySelector, Func, TResult> resultSelector, IEqualityComparer comparer) { CheckNotNull(outer, "outer"); CheckNotNull(inner, "inner"); CheckNotNull(outerKeySelector, "outerKeySelector"); CheckNotNull(innerKeySelector, "innerKeySelector"); CheckNotNull(resultSelector, "resultSelector"); var lookup = inner.ToLookup(innerKeySelector, comparer); return outer.Select(o => resultSelector(o, lookup[outerKeySelector(o)])); } [DebuggerStepThrough] private static void CheckNotNull(T value, string name) where T : class { if (value == null) throw new ArgumentNullException(name); } private static class Sequence { public static readonly IEnumerable Empty = new T[0]; } private sealed class Grouping : List, IGrouping { internal Grouping(K key) { Key = key; } public K Key { get; private set; } } } internal partial class Enumerable { /// /// Computes the sum of a sequence of values. /// public static int Sum( this IEnumerable source) { CheckNotNull(source, "source"); int sum = 0; foreach (var num in source) sum = checked(sum + num); return sum; } /// /// Computes the sum of a sequence of /// values that are obtained by invoking a transform function on /// each element of the input sequence. /// public static int Sum( this IEnumerable source, Func selector) { return source.Select(selector).Sum(); } /// /// Computes the average of a sequence of values. /// public static double Average( this IEnumerable source) { CheckNotNull(source, "source"); long sum = 0; long count = 0; foreach (var num in source) checked { sum += (int) num; count++; } if (count == 0) throw new InvalidOperationException(); return (double) sum/count; } /// /// Computes the average of a sequence of values /// that are obtained by invoking a transform function on each /// element of the input sequence. /// public static double Average( this IEnumerable source, Func selector) { return source.Select(selector).Average(); } /// /// Computes the sum of a sequence of nullable values. /// public static int? Sum( this IEnumerable source) { CheckNotNull(source, "source"); int sum = 0; foreach (var num in source) sum = checked(sum + (num ?? 0)); return sum; } /// /// Computes the sum of a sequence of nullable /// values that are obtained by invoking a transform function on /// each element of the input sequence. /// public static int? Sum( this IEnumerable source, Func selector) { return source.Select(selector).Sum(); } /// /// Computes the average of a sequence of nullable values. /// public static double? Average( this IEnumerable source) { CheckNotNull(source, "source"); long sum = 0; long count = 0; foreach (var num in source.Where(n => n != null)) checked { sum += (int) num; count++; } if (count == 0) return null; return (double?) sum/count; } /// /// Computes the average of a sequence of nullable values /// that are obtained by invoking a transform function on each /// element of the input sequence. /// public static double? Average( this IEnumerable source, Func selector) { return source.Select(selector).Average(); } /// /// Returns the minimum value in a sequence of nullable /// values. /// public static int? Min( this IEnumerable source) { CheckNotNull(source, "source"); return MinMaxImpl(source.Where(x => x != null), null, (min, x) => min < x); } /// /// Invokes a transform function on each element of a sequence and /// returns the minimum nullable value. /// public static int? Min( this IEnumerable source, Func selector) { return source.Select(selector).Min(); } /// /// Returns the maximum value in a sequence of nullable /// values. /// public static int? Max( this IEnumerable source) { CheckNotNull(source, "source"); return MinMaxImpl(source.Where(x => x != null), null, (max, x) => x == null || (max != null && x.Value < max.Value)); } /// /// Invokes a transform function on each element of a sequence and /// returns the maximum nullable value. /// public static int? Max( this IEnumerable source, Func selector) { return source.Select(selector).Max(); } /// /// Computes the sum of a sequence of values. /// public static long Sum( this IEnumerable source) { CheckNotNull(source, "source"); long sum = 0; foreach (var num in source) sum = checked(sum + num); return sum; } /// /// Computes the sum of a sequence of /// values that are obtained by invoking a transform function on /// each element of the input sequence. /// public static long Sum( this IEnumerable source, Func selector) { return source.Select(selector).Sum(); } /// /// Computes the average of a sequence of values. /// public static double Average( this IEnumerable source) { CheckNotNull(source, "source"); long sum = 0; long count = 0; foreach (var num in source) checked { sum += (long) num; count++; } if (count == 0) throw new InvalidOperationException(); return (double) sum/count; } /// /// Computes the average of a sequence of values /// that are obtained by invoking a transform function on each /// element of the input sequence. /// public static double Average( this IEnumerable source, Func selector) { return source.Select(selector).Average(); } /// /// Computes the sum of a sequence of nullable values. /// public static long? Sum( this IEnumerable source) { CheckNotNull(source, "source"); long sum = 0; foreach (var num in source) sum = checked(sum + (num ?? 0)); return sum; } /// /// Computes the sum of a sequence of nullable /// values that are obtained by invoking a transform function on /// each element of the input sequence. /// public static long? Sum( this IEnumerable source, Func selector) { return source.Select(selector).Sum(); } /// /// Computes the average of a sequence of nullable values. /// public static double? Average( this IEnumerable source) { CheckNotNull(source, "source"); long sum = 0; long count = 0; foreach (var num in source.Where(n => n != null)) checked { sum += (long) num; count++; } if (count == 0) return null; return (double?) sum/count; } /// /// Computes the average of a sequence of nullable values /// that are obtained by invoking a transform function on each /// element of the input sequence. /// public static double? Average( this IEnumerable source, Func selector) { return source.Select(selector).Average(); } /// /// Returns the minimum value in a sequence of nullable /// values. /// public static long? Min( this IEnumerable source) { CheckNotNull(source, "source"); return MinMaxImpl(source.Where(x => x != null), null, (min, x) => min < x); } /// /// Invokes a transform function on each element of a sequence and /// returns the minimum nullable value. /// public static long? Min( this IEnumerable source, Func selector) { return source.Select(selector).Min(); } /// /// Returns the maximum value in a sequence of nullable /// values. /// public static long? Max( this IEnumerable source) { CheckNotNull(source, "source"); return MinMaxImpl(source.Where(x => x != null), null, (max, x) => x == null || (max != null && x.Value < max.Value)); } /// /// Invokes a transform function on each element of a sequence and /// returns the maximum nullable value. /// public static long? Max( this IEnumerable source, Func selector) { return source.Select(selector).Max(); } /// /// Computes the sum of a sequence of nullable values. /// public static float Sum( this IEnumerable source) { CheckNotNull(source, "source"); float sum = 0; foreach (var num in source) sum = checked(sum + num); return sum; } /// /// Computes the sum of a sequence of /// values that are obtained by invoking a transform function on /// each element of the input sequence. /// public static float Sum( this IEnumerable source, Func selector) { return source.Select(selector).Sum(); } /// /// Computes the average of a sequence of values. /// public static float Average( this IEnumerable source) { CheckNotNull(source, "source"); float sum = 0; long count = 0; foreach (var num in source) checked { sum += (float) num; count++; } if (count == 0) throw new InvalidOperationException(); return (float) sum/count; } /// /// Computes the average of a sequence of values /// that are obtained by invoking a transform function on each /// element of the input sequence. /// public static float Average( this IEnumerable source, Func selector) { return source.Select(selector).Average(); } /// /// Computes the sum of a sequence of nullable values. /// public static float? Sum( this IEnumerable source) { CheckNotNull(source, "source"); float sum = 0; foreach (var num in source) sum = checked(sum + (num ?? 0)); return sum; } /// /// Computes the sum of a sequence of nullable /// values that are obtained by invoking a transform function on /// each element of the input sequence. /// public static float? Sum( this IEnumerable source, Func selector) { return source.Select(selector).Sum(); } /// /// Computes the average of a sequence of nullable values. /// public static float? Average( this IEnumerable source) { CheckNotNull(source, "source"); float sum = 0; long count = 0; foreach (var num in source.Where(n => n != null)) checked { sum += (float) num; count++; } if (count == 0) return null; return (float?) sum/count; } /// /// Computes the average of a sequence of nullable values /// that are obtained by invoking a transform function on each /// element of the input sequence. /// public static float? Average( this IEnumerable source, Func selector) { return source.Select(selector).Average(); } /// /// Returns the minimum value in a sequence of nullable /// values. /// public static float? Min( this IEnumerable source) { CheckNotNull(source, "source"); return MinMaxImpl(source.Where(x => x != null), null, (min, x) => min < x); } /// /// Invokes a transform function on each element of a sequence and /// returns the minimum nullable value. /// public static float? Min( this IEnumerable source, Func selector) { return source.Select(selector).Min(); } /// /// Returns the maximum value in a sequence of nullable /// values. /// public static float? Max( this IEnumerable source) { CheckNotNull(source, "source"); return MinMaxImpl(source.Where(x => x != null), null, (max, x) => x == null || (max != null && x.Value < max.Value)); } /// /// Invokes a transform function on each element of a sequence and /// returns the maximum nullable value. /// public static float? Max( this IEnumerable source, Func selector) { return source.Select(selector).Max(); } /// /// Computes the sum of a sequence of values. /// public static double Sum( this IEnumerable source) { CheckNotNull(source, "source"); double sum = 0; foreach (var num in source) sum = checked(sum + num); return sum; } /// /// Computes the sum of a sequence of /// values that are obtained by invoking a transform function on /// each element of the input sequence. /// public static double Sum( this IEnumerable source, Func selector) { return source.Select(selector).Sum(); } /// /// Computes the average of a sequence of values. /// public static double Average( this IEnumerable source) { CheckNotNull(source, "source"); double sum = 0; long count = 0; foreach (var num in source) checked { sum += (double) num; count++; } if (count == 0) throw new InvalidOperationException(); return (double) sum/count; } /// /// Computes the average of a sequence of values /// that are obtained by invoking a transform function on each /// element of the input sequence. /// public static double Average( this IEnumerable source, Func selector) { return source.Select(selector).Average(); } /// /// Computes the sum of a sequence of nullable values. /// public static double? Sum( this IEnumerable source) { CheckNotNull(source, "source"); double sum = 0; foreach (var num in source) sum = checked(sum + (num ?? 0)); return sum; } /// /// Computes the sum of a sequence of nullable /// values that are obtained by invoking a transform function on /// each element of the input sequence. /// public static double? Sum( this IEnumerable source, Func selector) { return source.Select(selector).Sum(); } /// /// Computes the average of a sequence of nullable values. /// public static double? Average( this IEnumerable source) { CheckNotNull(source, "source"); double sum = 0; long count = 0; foreach (var num in source.Where(n => n != null)) checked { sum += (double) num; count++; } if (count == 0) return null; return (double?) sum/count; } /// /// Computes the average of a sequence of nullable values /// that are obtained by invoking a transform function on each /// element of the input sequence. /// public static double? Average( this IEnumerable source, Func selector) { return source.Select(selector).Average(); } /// /// Returns the minimum value in a sequence of nullable /// values. /// public static double? Min( this IEnumerable source) { CheckNotNull(source, "source"); return MinMaxImpl(source.Where(x => x != null), null, (min, x) => min < x); } /// /// Invokes a transform function on each element of a sequence and /// returns the minimum nullable value. /// public static double? Min( this IEnumerable source, Func selector) { return source.Select(selector).Min(); } /// /// Returns the maximum value in a sequence of nullable /// values. /// public static double? Max( this IEnumerable source) { CheckNotNull(source, "source"); return MinMaxImpl(source.Where(x => x != null), null, (max, x) => x == null || (max != null && x.Value < max.Value)); } /// /// Invokes a transform function on each element of a sequence and /// returns the maximum nullable value. /// public static double? Max( this IEnumerable source, Func selector) { return source.Select(selector).Max(); } /// /// Computes the sum of a sequence of values. /// public static decimal Sum( this IEnumerable source) { CheckNotNull(source, "source"); decimal sum = 0; foreach (var num in source) sum = checked(sum + num); return sum; } /// /// Computes the sum of a sequence of /// values that are obtained by invoking a transform function on /// each element of the input sequence. /// public static decimal Sum( this IEnumerable source, Func selector) { CheckNotNull(source, "source"); CheckNotNull(selector, "selector"); decimal sum = 0; foreach (TSource item in source) { sum += selector(item); } return sum; } /// /// Computes the average of a sequence of values. /// public static decimal Average( this IEnumerable source) { CheckNotNull(source, "source"); decimal sum = 0; long count = 0; foreach (var num in source) checked { sum += (decimal) num; count++; } if (count == 0) throw new InvalidOperationException(); return (decimal) sum/count; } /// /// Computes the average of a sequence of values /// that are obtained by invoking a transform function on each /// element of the input sequence. /// public static decimal Average( this IEnumerable source, Func selector) { return source.Select(selector).Average(); } /// /// Computes the sum of a sequence of nullable values. /// public static decimal? Sum( this IEnumerable source) { CheckNotNull(source, "source"); decimal sum = 0; foreach (var num in source) sum = checked(sum + (num ?? 0)); return sum; } /// /// Computes the sum of a sequence of nullable /// values that are obtained by invoking a transform function on /// each element of the input sequence. /// public static decimal? Sum( this IEnumerable source, Func selector) { return source.Select(selector).Sum(); } /// /// Computes the average of a sequence of nullable values. /// public static decimal? Average( this IEnumerable source) { CheckNotNull(source, "source"); decimal sum = 0; long count = 0; foreach (var num in source.Where(n => n != null)) checked { sum += (decimal) num; count++; } if (count == 0) return null; return (decimal?) sum/count; } /// /// Computes the average of a sequence of nullable values /// that are obtained by invoking a transform function on each /// element of the input sequence. /// public static decimal? Average( this IEnumerable source, Func selector) { return source.Select(selector).Average(); } /// /// Returns the minimum value in a sequence of nullable /// values. /// public static decimal? Min( this IEnumerable source) { CheckNotNull(source, "source"); return MinMaxImpl(source.Where(x => x != null), null, (min, x) => min < x); } /// /// Invokes a transform function on each element of a sequence and /// returns the minimum nullable value. /// public static decimal? Min( this IEnumerable source, Func selector) { return source.Select(selector).Min(); } /// /// Returns the maximum value in a sequence of nullable /// values. /// public static decimal? Max( this IEnumerable source) { CheckNotNull(source, "source"); return MinMaxImpl(source.Where(x => x != null), null, (max, x) => x == null || (max != null && x.Value < max.Value)); } /// /// Invokes a transform function on each element of a sequence and /// returns the maximum nullable value. /// public static decimal? Max( this IEnumerable source, Func selector) { return source.Select(selector).Max(); } } /// /// Represents a collection of objects that have a common key. /// internal partial interface IGrouping : IEnumerable { /// /// Gets the key of the . /// TKey Key { get; } } /// /// Defines an indexer, size property, and Boolean search method for /// data structures that map keys to /// sequences of values. /// internal partial interface ILookup : IEnumerable> { bool Contains(TKey key); int Count { get; } IEnumerable this[TKey key] { get; } } /// /// Represents a sorted sequence. /// internal partial interface IOrderedEnumerable : IEnumerable { /// /// Performs a subsequent ordering on the elements of an /// according to a key. /// IOrderedEnumerable CreateOrderedEnumerable( Func keySelector, IComparer comparer, bool descending); } /// /// Represents a collection of keys each mapped to one or more values. /// internal sealed class Lookup : ILookup { private readonly Dictionary> _map; internal Lookup(IEqualityComparer comparer) { _map = new Dictionary>(comparer); } internal void Add(IGrouping item) { _map.Add(item.Key, item); } internal IEnumerable Find(TKey key) { IGrouping grouping; return _map.TryGetValue(key, out grouping) ? grouping : null; } /// /// Gets the number of key/value collection pairs in the . /// public int Count => _map.Count; /// /// Gets the collection of values indexed by the specified key. /// public IEnumerable this[TKey key] { get { IGrouping result; return _map.TryGetValue(key, out result) ? result : Enumerable.Empty(); } } /// /// Determines whether a specified key is in the . /// public bool Contains(TKey key) { return _map.ContainsKey(key); } /// /// Applies a transform function to each key and its associated /// values and returns the results. /// public IEnumerable ApplyResultSelector( Func, TResult> resultSelector) { if (resultSelector == null) throw new ArgumentNullException("resultSelector"); foreach (var pair in _map) yield return resultSelector(pair.Key, pair.Value); } /// /// Returns a generic enumerator that iterates through the . /// public IEnumerator> GetEnumerator() { return _map.Values.GetEnumerator(); } IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } } internal sealed class OrderedEnumerable : IOrderedEnumerable { private readonly IEnumerable _source; private readonly List> _comparisons; public OrderedEnumerable(IEnumerable source, Func keySelector, IComparer comparer, bool descending) : this(source, null, keySelector, comparer, descending) { } private OrderedEnumerable(IEnumerable source, List> comparisons, Func keySelector, IComparer comparer, bool descending) { if (source == null) throw new ArgumentNullException("source"); if (keySelector == null) throw new ArgumentNullException("keySelector"); _source = source; comparer = comparer ?? Comparer.Default; if (comparisons == null) comparisons = new List>( /* capacity */ 4); comparisons.Add((x, y) => (descending ? -1 : 1)*comparer.Compare(keySelector(x), keySelector(y))); _comparisons = comparisons; } public IOrderedEnumerable CreateOrderedEnumerable( Func keySelector, IComparer comparer, bool descending) { return new OrderedEnumerable(_source, _comparisons, keySelector, comparer, descending); } public IEnumerator GetEnumerator() { // // We sort using List.Sort, but docs say that it performs an // unstable sort. LINQ, on the other hand, says OrderBy performs // a stable sort. So convert the source sequence into a sequence // of tuples where the second element tags the position of the // element from the source sequence (First). The position is // then used as a tie breaker when all keys compare equal, // thus making the sort stable. // var list = _source.Select(new Func>(TagPosition)).ToList(); list.Sort((x, y) => { // // Compare keys from left to right. // var comparisons = _comparisons; for (var i = 0; i < comparisons.Count; i++) { var result = comparisons[i](x.First, y.First); if (result != 0) return result; } // // All keys compared equal so now break the tie by their // position in the original sequence, making the sort stable. // return x.Second.CompareTo(y.Second); }); return list.Select(new Func, T>(GetFirst)).GetEnumerator(); } /// /// See issue #11 /// for why this method is needed and cannot be expressed as a /// lambda at the call site. /// private static Tuple TagPosition(T e, int i) { return new Tuple(e, i); } /// /// See issue #11 /// for why this method is needed and cannot be expressed as a /// lambda at the call site. /// private static T GetFirst(Tuple pv) { return pv.First; } IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } } [Serializable] internal readonly struct Tuple : IEquatable> { public TFirst First { get; } public TSecond Second { get; } public Tuple(TFirst first, TSecond second) : this() { First = first; Second = second; } public override bool Equals(object obj) { return obj != null && obj is Tuple && base.Equals((Tuple) obj); } public bool Equals(Tuple other) { return EqualityComparer.Default.Equals(other.First, First) && EqualityComparer.Default.Equals(other.Second, Second); } public override int GetHashCode() { var num = 0x7a2f0b42; num = (-1521134295*num) + EqualityComparer.Default.GetHashCode(First); return (-1521134295*num) + EqualityComparer.Default.GetHashCode(Second); } public override string ToString() { return string.Format(CultureInfo.InvariantCulture, @"{{ First = {0}, Second = {1} }}", First, Second); } } } namespace LC.Newtonsoft.Json.Serialization { #pragma warning disable 1591 public delegate TResult Func(); public delegate TResult Func(T a); public delegate TResult Func(T1 arg1, T2 arg2); public delegate TResult Func(T1 arg1, T2 arg2, T3 arg3); public delegate TResult Func(T1 arg1, T2 arg2, T3 arg3, T4 arg4); public delegate void Action(); public delegate void Action(T1 arg1, T2 arg2); public delegate void Action(T1 arg1, T2 arg2, T3 arg3); public delegate void Action(T1 arg1, T2 arg2, T3 arg3, T4 arg4); #pragma warning restore 1591 } namespace System.Runtime.CompilerServices { /// /// This attribute allows us to define extension methods without /// requiring .NET Framework 3.5. For more information, see the section, /// Extension Methods in .NET Framework 2.0 Apps, /// of Basic Instincts: Extension Methods /// column in MSDN Magazine, /// issue Nov 2007. /// [AttributeUsage(AttributeTargets.Method | AttributeTargets.Class | AttributeTargets.Assembly)] internal sealed class ExtensionAttribute : Attribute { } } #endif