2008-09-11 Jb Evain <jbevain@novell.com>
[mono.git] / mcs / class / System.Core / System.Linq / Enumerable.cs
index ab6f16a65c6bc65d1485f6567f2ea399db594629..4d46b21bc0a431d5927645d9739417f6694e4e10 100644 (file)
@@ -40,6 +40,15 @@ namespace System.Linq
 {
        public static class Enumerable
        {
+               enum Fallback {
+                       Default,
+                       Throw
+               }
+
+               class PredicateOf<T> {
+                       public static readonly Func<T, bool> Always = (t) => true;
+               }
+
                #region Aggregate
 
                public static TSource Aggregate<TSource> (this IEnumerable<TSource> source, Func<TSource, TSource, TSource> func)
@@ -77,8 +86,8 @@ namespace System.Linq
                        if (resultSelector == null)
                                throw new ArgumentNullException ("resultSelector");
 
-                       TAccumulate result = seed;
-                       foreach (TSource e in source)
+                       var result = seed;
+                       foreach (var e in source)
                                result = func (result, e);
 
                        return resultSelector (result);
@@ -92,7 +101,7 @@ namespace System.Linq
                {
                        Check.SourceAndPredicate (source, predicate);
 
-                       foreach (TSource element in source)
+                       foreach (var element in source)
                                if (!predicate (element))
                                        return false;
 
@@ -137,35 +146,39 @@ namespace System.Linq
 
                public static double Average (this IEnumerable<int> source)
                {
-                       return Average (source, (a, b) => a + b, (a, b) => a / b);
+                       return Average<int, long, double> (source, (a, b) => a + b, (a, b) => (double) a / (double) b);
                }
 
                public static double Average (this IEnumerable<long> source)
                {
-                       return Average (source, (a, b) => a + b, (a, b) => a / b);
+                       return Average<long, long, double> (source, (a, b) => a + b, (a, b) => (double) a / (double) b);
                }
 
                public static double Average (this IEnumerable<double> source)
                {
-                       return Average (source, (a, b) => a + b, (a, b) => a / b);
+                       return Average<double, double, double> (source, (a, b) => a + b, (a, b) => a / b);
                }
 
                public static float Average (this IEnumerable<float> source)
                {
-                       return Average (source, (a, b) => a + b, (a, b) => a / b);
+                       return Average<float, double, float> (source, (a, b) => a + b, (a, b) => (float) a / (float) b);
                }
 
                public static decimal Average (this IEnumerable<decimal> source)
                {
-                       return Average (source, (a, b) => a + b, (a, b) => a / b);
+                       return Average<decimal, decimal, decimal> (source, (a, b) => a + b, (a, b) => a / b);
                }
 
-               static TR Average<TA, TR> (this IEnumerable<TA> source, Func<TA, TA, TA> func, Func<TA, int, TR> result)
+               static TResult Average<TElement, TAggregate, TResult> (this IEnumerable<TElement> source,
+                       Func<TAggregate, TElement, TAggregate> func, Func<TAggregate, long, TResult> result)
+                       where TElement : struct
+                       where TAggregate : struct
+                       where TResult : struct
                {
                        Check.Source (source);
 
-                       TA total = default (TA);
-                       int counter = 0;
+                       var total = default (TAggregate);
+                       long counter = 0;
                        foreach (var element in source) {
                                total = func (total, element);
                                ++counter;
@@ -177,269 +190,135 @@ namespace System.Linq
                        return result (total, counter);
                }
 
-               public static double? Average (this IEnumerable<int?> source)
+               static TResult? AverageNullable<TElement, TAggregate, TResult> (this IEnumerable<TElement?> source,
+                       Func<TAggregate, TElement, TAggregate> func, Func<TAggregate, long, TResult> result)
+                       where TElement : struct
+                       where TAggregate : struct
+                       where TResult : struct
                {
                        Check.Source (source);
 
-                       bool onlyNull = true;
-                       long sum = 0;
+                       var total = default (TAggregate);
                        long counter = 0;
-                       foreach (int? element in source) {
-                               if (element.HasValue) {
-                                       onlyNull = false;
-                                       sum += element.Value;
-                                       counter++;
-                               }
+                       foreach (var element in source) {
+                               if (!element.HasValue)
+                                       continue;
+
+                               total = func (total, element.Value);
+                               counter++;
                        }
-                       return (onlyNull ? null : (double?) sum / (double?) counter);
+
+                       if (counter == 0)
+                               return null;
+
+                       return new TResult? (result (total, counter));
+               }
+
+               public static double? Average (this IEnumerable<int?> source)
+               {
+                       Check.Source (source);
+
+                       return source.AverageNullable<int, long, double> ((a, b) => a + b, (a, b) => (double) a / (double) b);
                }
 
                public static double? Average (this IEnumerable<long?> source)
                {
                        Check.Source (source);
 
-                       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);
+                       return source.AverageNullable<long, long, double> ((a, b) => a + b, (a, b) => a / b);
                }
 
                public static double? Average (this IEnumerable<double?> source)
                {
                        Check.Source (source);
 
-                       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));
+                       return source.AverageNullable<double, double, double> ((a, b) => a + b, (a, b) => a / b);
                }
 
                public static decimal? Average (this IEnumerable<decimal?> source)
                {
                        Check.Source (source);
 
-                       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));
+                       return source.AverageNullable<decimal, decimal, decimal> ((a, b) => a + b, (a, b) => a / b);
                }
 
                public static float? Average (this IEnumerable<float?> source)
                {
                        Check.Source (source);
 
-                       float sum = 0;
-                       float counter = 0;
-                       foreach (float? element in source) {
-                               if (element.HasValue) {
-                                       sum += element.Value;
-                                       ++counter;
-                               }
-                       }
-
-                       if (counter == 0)
-                               return null;
-
-                       return sum / counter;
+                       return source.AverageNullable<float, double, float> ((a, b) => a + b, (a, b) => (float) a / (float) b);
                }
 
                public static double Average<TSource> (this IEnumerable<TSource> source, Func<TSource, int> selector)
                {
                        Check.SourceAndSelector (source, selector);
 
-                       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;
+                       return source.Select (selector).Average<int, long, double> ((a, b) => a + b, (a, b) => (double) a / (double) b);
                }
 
                public static double? Average<TSource> (this IEnumerable<TSource> source, Func<TSource, int?> selector)
                {
                        Check.SourceAndSelector (source, selector);
 
-                       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);
+                       return source.Select (selector).AverageNullable<int, long, double> ((a, b) => a + b, (a, b) => (double) a / (double) b);
                }
 
                public static double Average<TSource> (this IEnumerable<TSource> source, Func<TSource, long> selector)
                {
                        Check.SourceAndSelector (source, selector);
 
-                       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;
+                       return source.Select (selector).Average<long, long, double> ((a, b) => a + b, (a, b) => (double) a / (double) b);
                }
 
                public static double? Average<TSource> (this IEnumerable<TSource> source, Func<TSource, long?> selector)
                {
                        Check.SourceAndSelector (source, selector);
 
-                       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);
+                       return source.Select (selector).AverageNullable<long, long, double> ((a, b) => a + b, (a, b) => (double) a / (double) b);
                }
 
                public static double Average<TSource> (this IEnumerable<TSource> source, Func<TSource, double> selector)
                {
                        Check.SourceAndSelector (source, selector);
 
-                       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;
+                       return source.Select (selector).Average<double, double, double> ((a, b) => a + b, (a, b) => a / b);
                }
 
                public static double? Average<TSource> (this IEnumerable<TSource> source, Func<TSource, double?> selector)
                {
                        Check.SourceAndSelector (source, selector);
 
-                       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));
+                       return source.Select (selector).AverageNullable<double, double, double> ((a, b) => a + b, (a, b) => a / b);
                }
 
                public static float Average<TSource> (this IEnumerable<TSource> source, Func<TSource, float> selector)
                {
                        Check.SourceAndSelector (source, selector);
 
-                       float sum = 0;
-                       float counter = 0;
-                       foreach (TSource item in source) {
-                               sum += selector (item);
-                               ++counter;
-                       }
-
-                       if (counter == 0)
-                               throw new InvalidOperationException ();
-
-                       return sum / counter;
+                       return source.Select (selector).Average<float, double, float> ((a, b) => a + b, (a, b) => (float) a / (float) b);
                }
 
                public static float? Average<TSource> (this IEnumerable<TSource> source, Func<TSource, float?> selector)
                {
                        Check.SourceAndSelector (source, selector);
 
-                       float sum = 0;
-                       float counter = 0;
-                       foreach (TSource item in source) {
-                               float? value = selector (item);
-                               if (value.HasValue) {
-                                       sum  += value.Value;
-                                       ++counter;
-                               }
-                       }
-
-                       if (counter == 0)
-                               throw new InvalidOperationException ();
-
-                       return sum / counter;
+                       return source.Select (selector).AverageNullable<float, double, float> ((a, b) => a + b, (a, b) => (float) a / (float) b);
                }
 
                public static decimal Average<TSource> (this IEnumerable<TSource> source, Func<TSource, decimal> selector)
                {
                        Check.SourceAndSelector (source, selector);
 
-                       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;
+                       return source.Select (selector).Average<decimal, decimal, decimal> ((a, b) => a + b, (a, b) => a / b);
                }
 
                public static decimal? Average<TSource> (this IEnumerable<TSource> source, Func<TSource, decimal?> selector)
                {
                        Check.SourceAndSelector (source, selector);
 
-                       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));
+                       return source.Select (selector).AverageNullable<decimal, decimal, decimal> ((a, b) => a + b, (a, b) => a / b);
                }
+
                #endregion
 
                #region Cast
@@ -453,8 +332,8 @@ namespace System.Linq
 
                static IEnumerable<TResult> CreateCastIterator<TResult> (IEnumerable source)
                {
-                       foreach (object element in source)
-                               yield return (TResult) element;
+                       foreach (TResult element in source)
+                               yield return element;
                }
 
                #endregion
@@ -465,6 +344,11 @@ namespace System.Linq
                {
                        Check.FirstAndSecond (first, second);
 
+                       return CreateConcatIterator (first, second);
+               }
+
+               static IEnumerable<TSource> CreateConcatIterator<TSource> (IEnumerable<TSource> first, IEnumerable<TSource> second)
+               {
                        foreach (TSource element in first)
                                yield return element;
                        foreach (TSource element in second)
@@ -491,10 +375,9 @@ namespace System.Linq
                        if (comparer == null)
                                comparer = EqualityComparer<TSource>.Default;
 
-                       foreach (TSource e in source) {
-                               if (comparer.Equals (e, value))
+                       foreach (var element in source)
+                               if (comparer.Equals (element, value))
                                        return true;
-                       }
 
                        return false;
                }
@@ -579,9 +462,9 @@ namespace System.Linq
 
                static IEnumerable<TSource> CreateDistinctIterator<TSource> (IEnumerable<TSource> source, IEqualityComparer<TSource> comparer)
                {
-                       var items = new HashSet<TSource> ();
+                       var items = new HashSet<TSource> (comparer);
                        foreach (var element in source) {
-                               if (! items.Contains (element, comparer)) {
+                               if (! items.Contains (element)) {
                                        items.Add (element);
                                        yield return element;
                                }
@@ -592,9 +475,25 @@ namespace System.Linq
 
                #region ElementAt
 
+               static TSource ElementAt<TSource> (this IEnumerable<TSource> source, int index, Fallback fallback)
+               {
+                       long counter = 0L;
+
+                       foreach (var element in source) {
+                               if (index == counter++)
+                                       return element;
+                       }
+
+                       if (fallback == Fallback.Throw)
+                               throw new ArgumentOutOfRangeException ();
+
+                       return default (TSource);
+               }
+
                public static TSource ElementAt<TSource> (this IEnumerable<TSource> source, int index)
                {
                        Check.Source (source);
+
                        if (index < 0)
                                throw new ArgumentOutOfRangeException ();
 
@@ -602,14 +501,7 @@ namespace System.Linq
                        if (list != null)
                                return list [index];
 
-                       int counter = 0;
-                       foreach (var element in source) {
-                               if (counter == index)
-                                       return element;
-                               counter++;
-                       }
-
-                       throw new ArgumentOutOfRangeException ();
+                       return source.ElementAt (index, Fallback.Throw);
                }
 
                #endregion
@@ -619,6 +511,7 @@ namespace System.Linq
                public static TSource ElementAtOrDefault<TSource> (this IEnumerable<TSource> source, int index)
                {
                        Check.Source (source);
+
                        if (index < 0)
                                return default (TSource);
 
@@ -626,14 +519,7 @@ namespace System.Linq
                        if (list != null)
                                return index < list.Count ? list [index] : default (TSource);
 
-                       int counter = 0;
-                       foreach (TSource element in source) {
-                               if (counter == index)
-                                       return element;
-                               counter++;
-                       }
-
-                       return default (TSource);
+                       return source.ElementAt (index, Fallback.Default);
                }
 
                #endregion
@@ -666,9 +552,9 @@ namespace System.Linq
 
                static IEnumerable<TSource> CreateExceptIterator<TSource> (IEnumerable<TSource> first, IEnumerable<TSource> second, IEqualityComparer<TSource> comparer)
                {
-                       var items = new HashSet<TSource> (Distinct (second));
-                       foreach (TSource element in first) {
-                               if (! items.Contains (element, comparer))
+                       var items = new HashSet<TSource> (second, comparer);
+                       foreach (var element in first) {
+                               if (!items.Contains (element, comparer))
                                        yield return element;
                        }
                }
@@ -677,27 +563,43 @@ namespace System.Linq
 
                #region First
 
+               static TSource First<TSource> (this IEnumerable<TSource> source, Func<TSource, bool> predicate, Fallback fallback)
+               {
+                       foreach (var element in source)
+                               if (predicate (element))
+                                       return element;
+
+                       if (fallback == Fallback.Throw)
+                               throw new InvalidOperationException ();
+
+                       return default (TSource);
+               }
+
                public static TSource First<TSource> (this IEnumerable<TSource> source)
                {
                        Check.Source (source);
 
-                       foreach (TSource element in source)
-                               return element;
+                       var list = source as IList<TSource>;
+                       if (list != null) {
+                               if (list.Count != 0)
+                                       return list [0];
+
+                               throw new InvalidOperationException ();
+                       } else {
+                               using (var enumerator = source.GetEnumerator ()) {
+                                       if (enumerator.MoveNext ())
+                                               return enumerator.Current;
+                               }
+                       }
 
                        throw new InvalidOperationException ();
                }
 
-
                public static TSource First<TSource> (this IEnumerable<TSource> source, Func<TSource, bool> predicate)
                {
                        Check.SourceAndPredicate (source, predicate);
 
-                       foreach (TSource element in source) {
-                               if (predicate (element))
-                                       return element;
-                       }
-
-                       throw new InvalidOperationException ();
+                       return source.First (predicate, Fallback.Throw);
                }
 
                #endregion
@@ -708,23 +610,14 @@ namespace System.Linq
                {
                        Check.Source (source);
 
-                       foreach (TSource element in source)
-                               return element;
-
-                       return default (TSource);
+                       return source.First (PredicateOf<TSource>.Always, Fallback.Default);
                }
 
-
                public static TSource FirstOrDefault<TSource> (this IEnumerable<TSource> source, Func<TSource, bool> predicate)
                {
                        Check.SourceAndPredicate (source, predicate);
 
-                       foreach (TSource element in source) {
-                               if (predicate (element))
-                                       return element;
-                       }
-
-                       return default (TSource);
+                       return source.First (predicate, Fallback.Default);
                }
 
                #endregion
@@ -742,7 +635,6 @@ namespace System.Linq
                        return null;
                }
 
-
                public static IEnumerable<IGrouping<TKey, TSource>> GroupBy<TSource, TKey> (this IEnumerable<TSource> source,
                        Func<TSource, TKey> keySelector)
                {
@@ -754,6 +646,12 @@ namespace System.Linq
                {
                        Check.SourceAndKeySelector (source, keySelector);
 
+                       return CreateGroupByIterator (source, keySelector, comparer);
+               }
+
+               static IEnumerable<IGrouping<TKey, TSource>> CreateGroupByIterator<TSource, TKey> (this IEnumerable<TSource> source,
+                       Func<TSource, TKey> keySelector, IEqualityComparer<TKey> comparer)
+               {
                        Dictionary<TKey, List<TSource>> groups = new Dictionary<TKey, List<TSource>> ();
                        List<TSource> nullList = new List<TSource> ();
                        int counter = 0;
@@ -791,7 +689,6 @@ namespace System.Linq
                        }
                }
 
-
                public static IEnumerable<IGrouping<TKey, TElement>> GroupBy<TSource, TKey, TElement> (this IEnumerable<TSource> source,
                        Func<TSource, TKey> keySelector, Func<TSource, TElement> elementSelector)
                {
@@ -848,13 +745,16 @@ namespace System.Linq
                        return GroupBy (source, keySelector, elementSelector, resultSelector, null);
                }
 
-               [MonoTODO]
                public static IEnumerable<TResult> GroupBy<TSource, TKey, TElement, TResult> (this IEnumerable<TSource> source,
                        Func<TSource, TKey> keySelector, Func<TSource, TElement> elementSelector,
                        Func<TKey, IEnumerable<TElement>, TResult> resultSelector,
                        IEqualityComparer<TKey> comparer)
                {
-                       throw new NotImplementedException ();
+                       IEnumerable<IGrouping<TKey, TElement>> groups = GroupBy<TSource, TKey, TElement> (
+                               source, keySelector, elementSelector, comparer);
+
+                       foreach (IGrouping<TKey, TElement> group in groups)
+                               yield return resultSelector (group.Key, group);
                }
 
                public static IEnumerable<TResult> GroupBy<TSource, TKey, TResult> (this IEnumerable<TSource> source,
@@ -864,13 +764,15 @@ namespace System.Linq
                        return GroupBy (source, keySelector, resultSelector, null);
                }
 
-               [MonoTODO]
                public static IEnumerable<TResult> GroupBy<TSource, TKey, TResult> (this IEnumerable<TSource> source,
                        Func<TSource, TKey> keySelector,
                        Func<TKey, IEnumerable<TSource>, TResult> resultSelector,
                        IEqualityComparer<TKey> comparer)
                {
-                       throw new NotImplementedException ();
+                       IEnumerable<IGrouping<TKey,TSource>> groups = GroupBy<TSource, TKey> (source, keySelector, comparer);
+
+                       foreach (IGrouping<TKey, TSource> group in groups)
+                               yield return resultSelector (group.Key, group);
                }
 
                #endregion
@@ -894,6 +796,14 @@ namespace System.Linq
                        if (comparer == null)
                                comparer = EqualityComparer<TKey>.Default;
 
+                       return CreateGroupJoinIterator (outer, inner, outerKeySelector, innerKeySelector, resultSelector, comparer);
+               }
+
+               static IEnumerable<TResult> CreateGroupJoinIterator<TOuter, TInner, TKey, TResult> (this IEnumerable<TOuter> outer,
+                       IEnumerable<TInner> inner, Func<TOuter, TKey> outerKeySelector,
+                       Func<TInner, TKey> innerKeySelector, Func<TOuter, IEnumerable<TInner>, TResult> resultSelector,
+                       IEqualityComparer<TKey> comparer)
+               {
                        ILookup<TKey, TInner> innerKeys = ToLookup<TInner, TKey> (inner, innerKeySelector, comparer);
                        /*Dictionary<K, List<U>> innerKeys = new Dictionary<K, List<U>> ();
                        foreach (U element in inner)
@@ -934,9 +844,9 @@ namespace System.Linq
 
                static IEnumerable<TSource> CreateIntersectIterator<TSource> (IEnumerable<TSource> first, IEnumerable<TSource> second, IEqualityComparer<TSource> comparer)
                {
-                       List<TSource> items = new List<TSource> (Distinct (first));
-                       foreach (TSource element in second) {
-                               if (items.Contains (element, comparer))
+                       var items = new HashSet<TSource> (second, comparer);
+                       foreach (TSource element in first) {
+                               if (items.Contains (element))
                                        yield return element;
                        }
                }
@@ -954,6 +864,13 @@ namespace System.Linq
                        if (comparer == null)
                                comparer = EqualityComparer<TKey>.Default;
 
+                       return CreateJoinIterator (outer, inner, outerKeySelector, innerKeySelector, resultSelector, comparer);
+               }
+
+               static IEnumerable<TResult> CreateJoinIterator<TOuter, TInner, TKey, TResult> (this IEnumerable<TOuter> outer,
+                       IEnumerable<TInner> inner, Func<TOuter, TKey> outerKeySelector,
+                       Func<TInner, TKey> innerKeySelector, Func<TOuter, TInner, TResult> resultSelector, IEqualityComparer<TKey> comparer)
+               {
                        ILookup<TKey, TInner> innerKeys = ToLookup<TInner, TKey> (inner, innerKeySelector, comparer);
                        /*Dictionary<K, List<U>> innerKeys = new Dictionary<K, List<U>> ();
                        foreach (U element in inner)
@@ -977,48 +894,47 @@ namespace System.Linq
                        IEnumerable<TInner> inner, Func<TOuter, TKey> outerKeySelector,
                        Func<TInner, TKey> innerKeySelector, Func<TOuter, TInner, TResult> resultSelector)
                {
-                       return Join<TOuter, TInner, TKey, TResult> (outer, inner, outerKeySelector, innerKeySelector, resultSelector, null);
+                       return outer.Join (inner, outerKeySelector, innerKeySelector, resultSelector, null);
                }
 
-               # endregion
+               #endregion
 
                #region Last
 
-               public static TSource Last<TSource> (this IEnumerable<TSource> source)
+               static TSource Last<TSource> (this IEnumerable<TSource> source, Func<TSource, bool> predicate, Fallback fallback)
                {
-                       Check.Source (source);
+                       var empty = true;
+                       var item = default (TSource);
 
-                       bool noElements = true;
-                       TSource lastElement = default (TSource);
-                       foreach (TSource element in source) {
-                               if (noElements) noElements = false;
-                               lastElement = element;
+                       foreach (var element in source) {
+                               if (!predicate (element))
+                                       continue;
+
+                               item = element;
+                               empty = false;
                        }
 
-                       if (!noElements)
-                               return lastElement;
-                       else
+                       if (!empty)
+                               return item;
+
+                       if (fallback == Fallback.Throw)
                                throw new InvalidOperationException ();
+
+                       return item;
                }
 
-               public static TSource Last<TSource> (this IEnumerable<TSource> source,
-                               Func<TSource, bool> predicate)
+               public static TSource Last<TSource> (this IEnumerable<TSource> source)
                {
-                       Check.SourceAndPredicate (source, predicate);
+                       Check.Source (source);
 
-                       bool noElements = true;
-                       TSource lastElement = default (TSource);
-                       foreach (TSource element in source) {
-                               if (predicate (element)) {
-                                       if (noElements) noElements = false;
-                                       lastElement = element;
-                               }
-                       }
+                       return source.Last (PredicateOf<TSource>.Always, Fallback.Throw);
+               }
 
-                       if (!noElements)
-                               return lastElement;
-                       else
-                               throw new InvalidOperationException ();
+               public static TSource Last<TSource> (this IEnumerable<TSource> source, Func<TSource, bool> predicate)
+               {
+                       Check.SourceAndPredicate (source, predicate);
+
+                       return source.Last (predicate, Fallback.Throw);
                }
 
                #endregion
@@ -1033,34 +949,30 @@ namespace System.Linq
                        if (list != null)
                                return list.Count > 0 ? list [list.Count - 1] : default (TSource);
 
-                       TSource lastElement = default (TSource);
-                       foreach (TSource element in source)
-                               lastElement = element;
-
-                       return lastElement;
+                       return source.Last (PredicateOf<TSource>.Always, Fallback.Default);
                }
 
-               public static TSource LastOrDefault<TSource> (this IEnumerable<TSource> source,
-                       Func<TSource, bool> predicate)
+               public static TSource LastOrDefault<TSource> (this IEnumerable<TSource> source, Func<TSource, bool> predicate)
                {
                        Check.SourceAndPredicate (source, predicate);
 
-                       TSource lastElement = default (TSource);
-                       foreach (TSource element in source) {
-                               if (predicate (element))
-                                       lastElement = element;
-                       }
-
-                       return lastElement;
+                       return source.Last (predicate, Fallback.Default);
                }
 
                #endregion
 
                #region LongCount
+
                public static long LongCount<TSource> (this IEnumerable<TSource> source)
                {
                        Check.Source (source);
 
+#if !NET_2_1
+                       var array = source as TSource [];
+                       if (array != null)
+                               return array.LongLength;
+#endif
+
                        long counter = 0;
                        using (var enumerator = source.GetEnumerator ())
                                while (enumerator.MoveNext ())
@@ -1087,76 +999,77 @@ namespace System.Linq
 
                public static int Max (this IEnumerable<int> source)
                {
-                       return Iterate (source, int.MinValue, (a, b) => a > b);
+                       Check.Source (source);
+
+                       return Iterate (source, int.MinValue, (a, b) => Math.Max (a, b));
                }
 
                public static long Max (this IEnumerable<long> source)
                {
-                       return Iterate (source, long.MinValue, (a, b) => a > b);
+                       Check.Source (source);
+
+                       return Iterate (source, long.MinValue, (a, b) => Math.Max (a, b));
                }
 
                public static double Max (this IEnumerable<double> source)
                {
-                       return Iterate (source, double.MinValue, (a, b) => a > b);
+                       Check.Source (source);
+
+                       return Iterate (source, double.MinValue, (a, b) => Math.Max (a, b));
                }
 
                public static float Max (this IEnumerable<float> source)
                {
-                       return Iterate (source, float.MinValue, (a, b) => a > b);
-               }
+                       Check.Source (source);
 
-               public static decimal Max (this IEnumerable<decimal> source)
-               {
-                       return Iterate (source, decimal.MinValue, (a, b) => a > b);
+                       return Iterate (source, float.MinValue, (a, b) => Math.Max (a, b));
                }
 
-               static T Iterate<T> (IEnumerable<T> source, T initValue, Func<T, T, bool> selector)
+               public static decimal Max (this IEnumerable<decimal> source)
                {
-                       Check.SourceAndSelector (source, selector);
-
-                       int counter = 0;
-                       foreach (var element in source) {
-                               if (selector (element, initValue))
-                                       initValue = element;
-                               ++counter;
-                       }
-
-                       if (counter == 0)
-                               throw new InvalidOperationException ();
+                       Check.Source (source);
 
-                       return initValue;
+                       return Iterate (source, decimal.MinValue, (a, b) => Math.Max (a, b));
                }
 
                public static int? Max (this IEnumerable<int?> source)
                {
+                       Check.Source (source);
+
                        return IterateNullable (source, int.MinValue, (a, b) => a > b);
                }
 
                public static long? Max (this IEnumerable<long?> source)
                {
+                       Check.Source (source);
+
                        return IterateNullable (source, long.MinValue, (a, b) => a > b);
                }
 
                public static double? Max (this IEnumerable<double?> source)
                {
+                       Check.Source (source);
+
                        return IterateNullable (source, double.MinValue, (a, b) => a > b);
                }
 
                public static float? Max (this IEnumerable<float?> source)
                {
+                       Check.Source (source);
+
                        return IterateNullable (source, float.MinValue, (a, b) => a > b);
                }
 
                public static decimal? Max (this IEnumerable<decimal?> source)
                {
+                       Check.Source (source);
+
                        return IterateNullable (source, decimal.MinValue, (a, b) => a > b);
                }
 
                static T? IterateNullable<T> (IEnumerable<T?> source, T initValue, Func<T?, T?, bool> selector) where T : struct
                {
-                       Check.SourceAndSelector (source, selector);
-
-                       int counter = 0;
+                       bool empty = true;
                        T? value = initValue;
                        foreach (var element in source) {
                                if (!element.HasValue)
@@ -1164,10 +1077,11 @@ namespace System.Linq
 
                                if (selector (element.Value, value))
                                        value = element;
-                               ++counter;
+
+                               empty = false;
                        }
 
-                       if (counter == 0)
+                       if (empty)
                                return null;
 
                        return value;
@@ -1207,50 +1121,48 @@ namespace System.Linq
 
                public static int Max<TSource> (this IEnumerable<TSource> source, Func<TSource, int> selector)
                {
-                       return Iterate (source, int.MinValue, (a, b) => {
-                               var v = selector (a); return v > b ? v : b;
-                       });
+                       Check.SourceAndSelector (source, selector);
+
+                       return Iterate (source, int.MinValue, (a, b) => Math.Max (selector (a), b));
                }
 
                public static long Max<TSource> (this IEnumerable<TSource> source, Func<TSource, long> selector)
                {
-                       return Iterate (source, long.MinValue, (a, b) => {
-                               var v = selector (a); return v > b ? v : b;
-                       });
+                       Check.SourceAndSelector (source, selector);
+
+                       return Iterate (source, long.MinValue, (a, b) => Math.Max (selector (a), b));
                }
 
                public static double Max<TSource> (this IEnumerable<TSource> source, Func<TSource, double> selector)
                {
-                       return Iterate (source, double.MinValue, (a, b) => {
-                               var v = selector (a); return v > b ? v : b;
-                       });
+                       Check.SourceAndSelector (source, selector);
+
+                       return Iterate (source, double.MinValue, (a, b) => Math.Max (selector (a), b));
                }
 
                public static float Max<TSource> (this IEnumerable<TSource> source, Func<TSource, float> selector)
                {
-                       return Iterate (source, float.MinValue, (a, b) => {
-                               var v = selector (a); return v > b ? v : b;
-                       });
+                       Check.SourceAndSelector (source, selector);
+
+                       return Iterate (source, float.MinValue, (a, b) => Math.Max (selector (a), b));
                }
 
                public static decimal Max<TSource> (this IEnumerable<TSource> source, Func<TSource, decimal> selector)
                {
-                       return Iterate (source, decimal.MinValue, (a, b) => {
-                               var v = selector (a); return v > b ? v : b;
-                       });
+                       Check.SourceAndSelector (source, selector);
+
+                       return Iterate (source, decimal.MinValue, (a, b) => Math.Max (selector (a), b));
                }
 
                static U Iterate<T, U> (IEnumerable<T> source, U initValue, Func<T, U, U> selector)
                {
-                       Check.SourceAndSelector (source, selector);
-
-                       int counter = 0;
+                       bool empty = true;
                        foreach (var element in source) {
                                initValue = selector (element, initValue);
-                               ++counter;
+                               empty = false;
                        }
 
-                       if (counter == 0)
+                       if (empty)
                                throw new InvalidOperationException ();
 
                        return initValue;
@@ -1258,19 +1170,17 @@ namespace System.Linq
 
                static U? IterateNullable<T, U> (IEnumerable<T> source, U initialValue, Func<T, U?, U?> selector) where U : struct
                {
-                       Check.SourceAndSelector (source, selector);
-
-                       int counter = 0;
+                       bool empty = true;
                        U? value = initialValue;
                        foreach (var element in source) {
                                value = selector (element, value);
                                if (!value.HasValue)
                                        continue;
 
-                               ++counter;
+                               empty = false;
                        }
 
-                       if (counter == 0)
+                       if (empty)
                                return null;
 
                        return value;
@@ -1278,6 +1188,8 @@ namespace System.Linq
 
                public static int? Max<TSource> (this IEnumerable<TSource> source, Func<TSource, int?> selector)
                {
+                       Check.SourceAndSelector (source, selector);
+
                        return IterateNullable (source, int.MinValue, (a, b) => {
                                var v = selector (a); return v > b ? v : b;
                        });
@@ -1285,6 +1197,8 @@ namespace System.Linq
 
                public static long? Max<TSource> (this IEnumerable<TSource> source, Func<TSource, long?> selector)
                {
+                       Check.SourceAndSelector (source, selector);
+
                        return IterateNullable (source, long.MinValue, (a, b) => {
                                var v = selector (a); return v > b ? v : b;
                        });
@@ -1292,6 +1206,8 @@ namespace System.Linq
 
                public static double? Max<TSource> (this IEnumerable<TSource> source, Func<TSource, double?> selector)
                {
+                       Check.SourceAndSelector (source, selector);
+
                        return IterateNullable (source, double.MinValue, (a, b) => {
                                var v = selector (a); return v > b ? v : b;
                        });
@@ -1299,6 +1215,8 @@ namespace System.Linq
 
                public static float? Max<TSource> (this IEnumerable<TSource> source, Func<TSource, float?> selector)
                {
+                       Check.SourceAndSelector (source, selector);
+
                        return IterateNullable (source, float.MinValue, (a, b) => {
                                var v = selector (a); return v > b ? v : b;
                        });
@@ -1306,13 +1224,14 @@ namespace System.Linq
 
                public static decimal? Max<TSource> (this IEnumerable<TSource> source, Func<TSource, decimal?> selector)
                {
+                       Check.SourceAndSelector (source, selector);
+
                        return IterateNullable (source, decimal.MinValue, (a, b) => {
                                var v = selector (a); return v > b ? v : b;
                        });
                }
 
-               public static TResult Max<TSource, TResult> (this IEnumerable<TSource> source,
-                               Func<TSource, TResult> selector)
+               public static TResult Max<TSource, TResult> (this IEnumerable<TSource> source, Func<TSource, TResult> selector)
                {
                        Check.SourceAndSelector (source, selector);
 
@@ -1351,51 +1270,71 @@ namespace System.Linq
 
                public static int Min (this IEnumerable<int> source)
                {
-                       return Iterate (source, int.MaxValue, (a, b) => a < b);
+                       Check.Source (source);
+
+                       return Iterate (source, int.MaxValue, (a, b) => Math.Min (a, b));
                }
 
                public static long Min (this IEnumerable<long> source)
                {
-                       return Iterate (source, long.MaxValue, (a, b) => a < b);
+                       Check.Source (source);
+
+                       return Iterate (source, long.MaxValue, (a, b) => Math.Min (a, b));
                }
 
                public static double Min (this IEnumerable<double> source)
                {
-                       return Iterate (source, double.MaxValue, (a, b) => a < b);
+                       Check.Source (source);
+
+                       return Iterate (source, double.MaxValue, (a, b) => Math.Min (a, b));
                }
 
                public static float Min (this IEnumerable<float> source)
                {
-                       return Iterate (source, float.MaxValue, (a, b) => a < b);
+                       Check.Source (source);
+
+                       return Iterate (source, float.MaxValue, (a, b) => Math.Min (a, b));
                }
 
                public static decimal Min (this IEnumerable<decimal> source)
                {
-                       return Iterate (source, decimal.MaxValue, (a, b) => a < b);
+                       Check.Source (source);
+
+                       return Iterate (source, decimal.MaxValue, (a, b) => Math.Min (a, b));
                }
 
                public static int? Min (this IEnumerable<int?> source)
                {
+                       Check.Source (source);
+
                        return IterateNullable (source, int.MaxValue, (a, b) => a < b);
                }
 
                public static long? Min (this IEnumerable<long?> source)
                {
+                       Check.Source (source);
+
                        return IterateNullable (source, long.MaxValue, (a, b) => a < b);
                }
 
                public static double? Min (this IEnumerable<double?> source)
                {
+                       Check.Source (source);
+
                        return IterateNullable (source, double.MaxValue, (a, b) => a < b);
                }
 
                public static float? Min (this IEnumerable<float?> source)
                {
+                       Check.Source (source);
+
                        return IterateNullable (source, float.MaxValue, (a, b) => a < b);
                }
 
                public static decimal? Min (this IEnumerable<decimal?> source)
                {
+                       Check.Source (source);
+
                        return IterateNullable (source, decimal.MaxValue, (a, b) => a < b);
                }
 
@@ -1433,41 +1372,43 @@ namespace System.Linq
 
                public static int Min<TSource> (this IEnumerable<TSource> source, Func<TSource, int> selector)
                {
-                       return Iterate (source, int.MaxValue, (a, b) => {
-                               var v = selector (a); return v < b ? v : b;
-                       });
+                       Check.SourceAndSelector (source, selector);
+
+                       return Iterate (source, int.MaxValue, (a, b) => Math.Min (selector (a), b));
                }
 
                public static long Min<TSource> (this IEnumerable<TSource> source, Func<TSource, long> selector)
                {
-                       return Iterate (source, long.MaxValue, (a, b) => {
-                               var v = selector (a); return v < b ? v : b;
-                       });
+                       Check.SourceAndSelector (source, selector);
+
+                       return Iterate (source, long.MaxValue, (a, b) => Math.Min (selector (a), b));
                }
 
                public static double Min<TSource> (this IEnumerable<TSource> source, Func<TSource, double> selector)
                {
-                       return Iterate (source, double.MaxValue, (a, b) => {
-                               var v = selector (a); return v < b ? v : b;
-                       });
+                       Check.SourceAndSelector (source, selector);
+
+                       return Iterate (source, double.MaxValue, (a, b) => Math.Min (selector (a), b));
                }
 
                public static float Min<TSource> (this IEnumerable<TSource> source, Func<TSource, float> selector)
                {
-                       return Iterate (source, float.MaxValue, (a, b) => {
-                               var v = selector (a); return v < b ? v : b;
-                       });
+                       Check.SourceAndSelector (source, selector);
+
+                       return Iterate (source, float.MaxValue, (a, b) => Math.Min (selector (a), b));
                }
 
                public static decimal Min<TSource> (this IEnumerable<TSource> source, Func<TSource, decimal> selector)
                {
-                       return Iterate (source, decimal.MaxValue, (a, b) => {
-                               var v = selector (a); return v < b ? v : b;
-                       });
+                       Check.SourceAndSelector (source, selector);
+
+                       return Iterate (source, decimal.MaxValue, (a, b) => Math.Min (selector (a), b));
                }
 
                public static int? Min<TSource> (this IEnumerable<TSource> source, Func<TSource, int?> selector)
                {
+                       Check.SourceAndSelector (source, selector);
+
                        return IterateNullable (source, int.MaxValue, (a, b) => {
                                var v = selector (a); return v < b ? v : b;
                        });
@@ -1475,13 +1416,17 @@ namespace System.Linq
 
                public static long? Min<TSource> (this IEnumerable<TSource> source, Func<TSource, long?> selector)
                {
+                       Check.SourceAndSelector (source, selector);
+
                        return IterateNullable (source, long.MaxValue, (a, b) => {
                                var v = selector (a); return v < b ? v : b;
                        });
                }
 
-               public static double? Min<TSource> (this IEnumerable<TSource> source, Func<TSource, float?> selector)
+               public static float? Min<TSource> (this IEnumerable<TSource> source, Func<TSource, float?> selector)
                {
+                       Check.SourceAndSelector (source, selector);
+
                        return IterateNullable (source, float.MaxValue, (a, b) => {
                                var v = selector (a); return v < b ? v : b;
                        });
@@ -1489,6 +1434,8 @@ namespace System.Linq
 
                public static double? Min<TSource> (this IEnumerable<TSource> source, Func<TSource, double?> selector)
                {
+                       Check.SourceAndSelector (source, selector);
+
                        return IterateNullable (source, double.MaxValue, (a, b) => {
                                var v = selector (a); return v < b ? v : b;
                        });
@@ -1496,13 +1443,14 @@ namespace System.Linq
 
                public static decimal? Min<TSource> (this IEnumerable<TSource> source, Func<TSource, decimal?> selector)
                {
+                       Check.SourceAndSelector (source, selector);
+
                        return IterateNullable (source, decimal.MaxValue, (a, b) => {
                                var v = selector (a); return v < b ? v : b;
                        });
                }
 
-               public static TResult Min<TSource, TResult> (this IEnumerable<TSource> source,
-                               Func<TSource, TResult> selector)
+               public static TResult Min<TSource, TResult> (this IEnumerable<TSource> source, Func<TSource, TResult> selector)
                {
                        Check.SourceAndSelector (source, selector);
 
@@ -1563,15 +1511,13 @@ namespace System.Linq
                        return OrderBy<TSource, TKey> (source, keySelector, null);
                }
 
-
                public static IOrderedEnumerable<TSource> OrderBy<TSource, TKey> (this IEnumerable<TSource> source,
                                Func<TSource, TKey> keySelector,
                                IComparer<TKey> comparer)
                {
                        Check.SourceAndKeySelector (source, keySelector);
 
-                       return new InternalOrderedSequence<TSource, TKey> (
-                                       source, keySelector, comparer, false);
+                       return new OrderedSequence<TSource, TKey> (source, keySelector, comparer, SortDirection.Ascending);
                }
 
                #endregion
@@ -1584,14 +1530,12 @@ namespace System.Linq
                        return OrderByDescending<TSource, TKey> (source, keySelector, null);
                }
 
-
                public static IOrderedEnumerable<TSource> OrderByDescending<TSource, TKey> (this IEnumerable<TSource> source,
                                Func<TSource, TKey> keySelector, IComparer<TKey> comparer)
                {
                        Check.SourceAndKeySelector (source, keySelector);
 
-                       return new InternalOrderedSequence<TSource, TKey> (
-                                       source, keySelector, comparer, true);
+                       return new OrderedSequence<TSource, TKey> (source, keySelector, comparer, SortDirection.Descending);
                }
 
                #endregion
@@ -1637,21 +1581,23 @@ namespace System.Linq
 
                #endregion
 
-
                #region Reverse
 
                public static IEnumerable<TSource> Reverse<TSource> (this IEnumerable<TSource> source)
                {
                        Check.Source (source);
 
-                       return CreateReverseIterator (source);
+                       var list = source as IList<TSource>;
+                       if (list == null)
+                               list = new List<TSource> (source);
+
+                       return CreateReverseIterator (list);
                }
 
-               static IEnumerable<TSource> CreateReverseIterator<TSource> (IEnumerable<TSource> source)
+               static IEnumerable<TSource> CreateReverseIterator<TSource> (IList<TSource> source)
                {
-                       var list = new List<TSource> (source);
-                       list.Reverse ();
-                       return list;
+                       for (int i = source.Count; i > 0; --i)
+                               yield return source [i - 1];
                }
 
                #endregion
@@ -1667,7 +1613,7 @@ namespace System.Linq
 
                static IEnumerable<TResult> CreateSelectIterator<TSource, TResult> (IEnumerable<TSource> source, Func<TSource, TResult> selector)
                {
-                       foreach (TSource element in source)
+                       foreach (var element in source)
                                yield return selector (element);
                }
 
@@ -1716,7 +1662,7 @@ namespace System.Linq
                {
                        int counter = 0;
                        foreach (TSource element in source) {
-                               foreach (TResult item in selector (element, counter++))
+                               foreach (TResult item in selector (element, counter))
                                        yield return item;
                                counter++;
                        }
@@ -1759,44 +1705,40 @@ namespace System.Linq
 
                #region Single
 
-               public static TSource Single<TSource> (this IEnumerable<TSource> source)
+               static TSource Single<TSource> (this IEnumerable<TSource> source, Func<TSource, bool> predicate, Fallback fallback)
                {
-                       Check.Source (source);
+                       var found = false;
+                       var item = default (TSource);
 
-                       bool otherElement = false;
-                       TSource singleElement = default (TSource);
-                       foreach (TSource element in source) {
-                               if (otherElement) throw new InvalidOperationException ();
-                               if (!otherElement) otherElement = true;
-                               singleElement = element;
+                       foreach (var element in source) {
+                               if (!predicate (element))
+                                       continue;
+
+                               if (found)
+                                       throw new InvalidOperationException ();
+
+                               found = true;
+                               item = element;
                        }
 
-                       if (otherElement)
-                               return singleElement;
-                       else
+                       if (!found && fallback == Fallback.Throw)
                                throw new InvalidOperationException ();
+
+                       return item;
                }
 
+               public static TSource Single<TSource> (this IEnumerable<TSource> source)
+               {
+                       Check.Source (source);
+
+                       return source.Single (PredicateOf<TSource>.Always, Fallback.Throw);
+               }
 
-               public static TSource Single<TSource> (this IEnumerable<TSource> source,
-                               Func<TSource, bool> predicate)
+               public static TSource Single<TSource> (this IEnumerable<TSource> source, Func<TSource, bool> predicate)
                {
                        Check.SourceAndPredicate (source, predicate);
 
-                       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 ();
+                       return source.Single (predicate, Fallback.Throw);
                }
 
                #endregion
@@ -1807,34 +1749,14 @@ namespace System.Linq
                {
                        Check.Source (source);
 
-                       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;
+                       return source.Single (PredicateOf<TSource>.Always, Fallback.Default);
                }
 
-
-               public static TSource SingleOrDefault<TSource> (this IEnumerable<TSource> source,
-                               Func<TSource, bool> predicate)
+               public static TSource SingleOrDefault<TSource> (this IEnumerable<TSource> source, Func<TSource, bool> predicate)
                {
                        Check.SourceAndPredicate (source, predicate);
 
-                       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;
+                       return source.Single (predicate, Fallback.Default);
                }
 
                #endregion
@@ -1915,22 +1837,30 @@ namespace System.Linq
 
                public static int Sum (this IEnumerable<int> source)
                {
+                       Check.Source (source);
+
                        return Sum<int, int> (source, (a, b) => a + b);
                }
 
                public static int? Sum (this IEnumerable<int?> source)
                {
-                       return SumNullable<int?, int?> (source, (a, b) => a.HasValue ? a + b : a);
+                       Check.Source (source);
+
+                       return source.SumNullable<int?, int?> (0, (a, b) => a.HasValue ? a + b : a);
                }
 
                public static int Sum<TSource> (this IEnumerable<TSource> source, Func<TSource, int> selector)
                {
+                       Check.SourceAndSelector (source, selector);
+
                        return Sum<TSource, int> (source, (a, b) => a + selector (b));
                }
 
                public static int? Sum<TSource> (this IEnumerable<TSource> source, Func<TSource, int?> selector)
                {
-                       return SumNullable<TSource, int?> (source, (a, b) => {
+                       Check.SourceAndSelector (source, selector);
+
+                       return source.SumNullable<TSource, int?> (0, (a, b) => {
                                var value = selector (b);
                                return value.HasValue ? a + value.Value : a;
                        });
@@ -1938,22 +1868,30 @@ namespace System.Linq
 
                public static long Sum (this IEnumerable<long> source)
                {
+                       Check.Source (source);
+
                        return Sum<long, long> (source, (a, b) => a + b);
                }
 
                public static long? Sum (this IEnumerable<long?> source)
                {
-                       return SumNullable<long?, long?> (source, (a, b) => a.HasValue ? a + b : a);
+                       Check.Source (source);
+
+                       return source.SumNullable<long?, long?> (0, (a, b) => a.HasValue ? a + b : a);
                }
 
                public static long Sum<TSource> (this IEnumerable<TSource> source, Func<TSource, long> selector)
                {
+                       Check.SourceAndSelector (source, selector);
+
                        return Sum<TSource, long> (source, (a, b) => a + selector (b));
                }
 
                public static long? Sum<TSource> (this IEnumerable<TSource> source, Func<TSource, long?> selector)
                {
-                       return SumNullable<TSource, long?> (source, (a, b) => {
+                       Check.SourceAndSelector (source, selector);
+
+                       return source.SumNullable<TSource, long?> (0, (a, b) => {
                                var value = selector (b);
                                return value.HasValue ? a + value.Value : a;
                        });
@@ -1961,22 +1899,30 @@ namespace System.Linq
 
                public static double Sum (this IEnumerable<double> source)
                {
+                       Check.Source (source);
+
                        return Sum<double, double> (source, (a, b) => a + b);
                }
 
                public static double? Sum (this IEnumerable<double?> source)
                {
-                       return SumNullable<double?, double?> (source, (a, b) => a.HasValue ? a + b : a);
+                       Check.Source (source);
+
+                       return source.SumNullable<double?, double?> (0, (a, b) => a.HasValue ? a + b : a);
                }
 
                public static double Sum<TSource> (this IEnumerable<TSource> source, Func<TSource, double> selector)
                {
+                       Check.SourceAndSelector (source, selector);
+
                        return Sum<TSource, double> (source, (a, b) => a + selector (b));
                }
 
                public static double? Sum<TSource> (this IEnumerable<TSource> source, Func<TSource, double?> selector)
                {
-                       return SumNullable<TSource, double?> (source, (a, b) => {
+                       Check.SourceAndSelector (source, selector);
+
+                       return source.SumNullable<TSource, double?> (0, (a, b) => {
                                var value = selector (b);
                                return value.HasValue ? a + value.Value : a;
                        });
@@ -1984,22 +1930,30 @@ namespace System.Linq
 
                public static float Sum (this IEnumerable<float> source)
                {
+                       Check.Source (source);
+
                        return Sum<float, float> (source, (a, b) => a + b);
                }
 
                public static float? Sum (this IEnumerable<float?> source)
                {
-                       return SumNullable<float?, float?> (source, (a, b) => a.HasValue ? a + b : a);
+                       Check.Source (source);
+
+                       return source.SumNullable<float?, float?> (0, (a, b) => a.HasValue ? a + b : a);
                }
 
                public static float Sum<TSource> (this IEnumerable<TSource> source, Func<TSource, float> selector)
                {
+                       Check.SourceAndSelector (source, selector);
+
                        return Sum<TSource, float> (source, (a, b) => a + selector (b));
                }
 
                public static float? Sum<TSource> (this IEnumerable<TSource> source, Func<TSource, float?> selector)
                {
-                       return SumNullable<TSource, float?> (source, (a, b) => {
+                       Check.SourceAndSelector (source, selector);
+
+                       return source.SumNullable<TSource, float?> (0, (a, b) => {
                                var value = selector (b);
                                return value.HasValue ? a + value.Value : a;
                        });
@@ -2007,51 +1961,52 @@ namespace System.Linq
 
                public static decimal Sum (this IEnumerable<decimal> source)
                {
+                       Check.Source (source);
+
                        return Sum<decimal, decimal> (source, (a, b) => a + b);
                }
 
                public static decimal? Sum (this IEnumerable<decimal?> source)
                {
-                       return SumNullable<decimal?, decimal?> (source, (a, b) => a.HasValue ? a + b : a);
+                       Check.Source (source);
+
+                       return source.SumNullable<decimal?, decimal?> (0, (a, b) => a.HasValue ? a + b : a);
                }
 
                public static decimal Sum<TSource> (this IEnumerable<TSource> source, Func<TSource, decimal> selector)
                {
+                       Check.SourceAndSelector (source, selector);
+
                        return Sum<TSource, decimal> (source, (a, b) => a + selector (b));
                }
 
                public static decimal? Sum<TSource> (this IEnumerable<TSource> source, Func<TSource, decimal?> selector)
                {
-                       return SumNullable<TSource, decimal?> (source, (a, b) => {
+                       Check.SourceAndSelector (source, selector);
+
+                       return source.SumNullable<TSource, decimal?> (0, (a, b) => {
                                var value = selector (b);
                                return value.HasValue ? a + value.Value : a;
                        });
                }
 
-               static TR Sum<TA, TR> (this IEnumerable<TA> source, Func<TR, TA, TR> func)
+               static TR Sum<TA, TR> (this IEnumerable<TA> source, Func<TR, TA, TR> selector)
                {
-                       Check.Source (source);
-
                        TR total = default (TR);
-                       int counter = 0;
+                       long counter = 0;
                        foreach (var element in source) {
-                               total = func (total, element);
+                               total = selector (total, element);
                                ++counter;
                        }
 
-                       if (counter == 0)
-                               throw new InvalidOperationException ();
-
                        return total;
                }
 
-               static TR SumNullable<TA, TR> (this IEnumerable<TA> source, Func<TR, TA, TR> func)
+               static TR SumNullable<TA, TR> (this IEnumerable<TA> source, TR zero, Func<TR, TA, TR> selector)
                {
-                       Check.Source (source);
-
-                       TR total = default (TR);
+                       TR total = zero;
                        foreach (var element in source) {
-                               total = func (total, element);
+                               total = selector (total, element);
                        }
 
                        return total;
@@ -2075,10 +2030,10 @@ namespace System.Linq
 
                        int counter = 0;
                        foreach (TSource element in source) {
-                               if (counter++ == count)
-                                       yield break;
-
                                yield return element;
+
+                               if (++counter == count)
+                                       yield break;
                        }
                }
 
@@ -2095,7 +2050,7 @@ namespace System.Linq
 
                static IEnumerable<TSource> CreateTakeWhileIterator<TSource> (IEnumerable<TSource> source, Func<TSource, bool> predicate)
                {
-                       foreach (TSource element in source) {
+                       foreach (var element in source) {
                                if (!predicate (element))
                                        yield break;
 
@@ -2131,7 +2086,6 @@ namespace System.Linq
                        return ThenBy<TSource, TKey> (source, keySelector, null);
                }
 
-
                public static IOrderedEnumerable<TSource> ThenBy<TSource, TKey> (this IOrderedEnumerable<TSource> source,
                        Func<TSource, TKey> keySelector, IComparer<TKey> comparer)
                {
@@ -2150,7 +2104,6 @@ namespace System.Linq
                        return ThenByDescending<TSource, TKey> (source, keySelector, null);
                }
 
-
                public static IOrderedEnumerable<TSource> ThenByDescending<TSource, TKey> (this IOrderedEnumerable<TSource> source,
                        Func<TSource, TKey> keySelector, IComparer<TKey> comparer)
                {
@@ -2162,12 +2115,19 @@ namespace System.Linq
                #endregion
 
                #region ToArray
+
                public static TSource [] ToArray<TSource> (this IEnumerable<TSource> source)
                {
                        Check.Source (source);
 
-                       List<TSource> list = new List<TSource> (source);
-                       return list.ToArray ();
+                       var collection = source as ICollection<TSource>;
+                       if (collection != null) {
+                               var array = new TSource [collection.Count];
+                               collection.CopyTo (array, 0);
+                               return array;
+                       }
+
+                       return new List<TSource> (source).ToArray ();
                }
 
                #endregion
@@ -2184,6 +2144,9 @@ namespace System.Linq
                {
                        Check.SourceAndKeyElementSelectors (source, keySelector, elementSelector);
 
+                       if (comparer == null)
+                               comparer = EqualityComparer<TKey>.Default;
+
                        var dict = new Dictionary<TKey, TElement> (comparer);
                        foreach (var e in source)
                                dict.Add (keySelector (e), elementSelector (e));
@@ -2200,9 +2163,16 @@ namespace System.Linq
                public static Dictionary<TKey, TSource> ToDictionary<TSource, TKey> (this IEnumerable<TSource> source,
                                Func<TSource, TKey> keySelector, IEqualityComparer<TKey> comparer)
                {
-                       throw new NotImplementedException ();
-                       // FIXME: compiler issue
-                       //return ToDictionary (source, keySelector, (a) => a, comparer);
+                       Check.SourceAndKeySelector (source, keySelector);
+
+                       if (comparer == null)
+                               comparer = EqualityComparer<TKey>.Default;
+
+                       var dict = new Dictionary<TKey, TSource> (comparer);
+                       foreach (var e in source)
+                               dict.Add (keySelector (e), e);
+
+                       return dict;
                }
 
                #endregion
@@ -2316,9 +2286,9 @@ namespace System.Linq
 
                static IEnumerable<TSource> CreateUnionIterator<TSource> (IEnumerable<TSource> first, IEnumerable<TSource> second, IEqualityComparer<TSource> comparer)
                {
-                       var items = new HashSet<TSource> ();
+                       var items = new HashSet<TSource> (comparer);
                        foreach (var element in first) {
-                               if (! items.Contains (element, comparer)) {
+                               if (! items.Contains (element)) {
                                        items.Add (element);
                                        yield return element;
                                }
@@ -2369,10 +2339,14 @@ namespace System.Linq
 
                #endregion
 
+               class ReadOnlyCollectionOf<T> {
+                       public static readonly ReadOnlyCollection<T> Empty = new ReadOnlyCollection<T> (new T [0]);
+               }
+
                internal static ReadOnlyCollection<TSource> ToReadOnlyCollection<TSource> (this IEnumerable<TSource> source)
                {
                        if (source == null)
-                               return new ReadOnlyCollection<TSource> (new TSource [0]); // could we singlotenize that?
+                               return ReadOnlyCollectionOf<TSource>.Empty;
 
                        var ro = source as ReadOnlyCollection<TSource>;
                        if (ro != null)