Click here to Skip to main content
15,883,949 members
Articles / Programming Languages / C#

Poor Man's LINQ in Visual Studio 2005

Rate me:
Please Sign up or sign in to vote.
4.53/5 (18 votes)
28 Oct 2010MIT3 min read 81.1K   619   34  
A way to use LINQ to Objects in C# 2.0 with .NET Framework 2.0
// Transferred from Mono to Loyc by David Piepgrass.

// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
// 
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
// 
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
//
// Authors:
//        Marek Safar (marek.safar@gmail.com)
//        Antonello Provenzano  <antonello@deveel.com>
//        Alejandro Serrano "Serras" (trupill@yahoo.es)

using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;

namespace Compatibility.Linq
{
	public delegate TResult Func<TResult>();
	public delegate TResult Func<TArg0, TResult>(TArg0 arg0);
	public delegate TResult Func<TArg0, TArg1, TResult>(TArg0 arg0, TArg1 arg1);
	public delegate TResult Func<TArg0, TArg1, TArg2, TResult>(TArg0 arg0, TArg1 arg1, TArg2 arg2);
	public delegate TResult Func<TArg0, TArg1, TArg2, TArg3, TResult>(TArg0 arg0, TArg1 arg1, TArg2 arg2, TArg3 arg3);

	public static class Enumerable
	{
        #region Aggregate
        public static TSource Aggregate<TSource>(/*this*/ IEnumerable<TSource> source, Func<TSource, TSource, TSource> func)
        {
            if (source == null || func == null)
                throw new ArgumentNullException();

            int counter = 0;
            TSource folded = default(TSource);

            foreach (TSource element in source)
            {
                if (counter == 0)
                    folded = element;
                else
                    folded = func(folded, element);
            }

            if (counter == 0)
                throw new InvalidOperationException();
            else
                return folded;
        }


        public static TAccumulate Aggregate<TSource, TAccumulate>(/*this*/ IEnumerable<TSource> source,
            TAccumulate seed, Func<TAccumulate, TSource, TAccumulate> func)
        {
            if (source == null || func == null)
                throw new ArgumentNullException();

            TAccumulate folded = seed;
            foreach (TSource element in source)
                folded = func(folded, element);
            return folded;
        }


        public static TResult Aggregate<TSource, TAccumulate, TResult>(/*this*/ IEnumerable<TSource> source, TAccumulate seed, Func<TAccumulate, TSource, TAccumulate> func, Func<TAccumulate, TResult> resultSelector)
        {
            if (source == null)
                throw new ArgumentNullException("source");
            if (func == null)
                throw new ArgumentNullException("func");
            if (resultSelector == null)
                throw new ArgumentNullException("resultSelector");

            TAccumulate result = seed;
            foreach (TSource e in source)
                result = func(result, e);
            return resultSelector(result);
        }
        #endregion

        #region All
        public static bool All<TSource>(/*this*/ IEnumerable<TSource> source, Func<TSource, bool> predicate)
        {
            if (source == null || predicate == null)
                throw new ArgumentNullException();

            foreach (TSource element in source)
                if (!predicate(element))
                    return false;
            return true;
        }
        #endregion

        #region Any
        public static bool Any<TSource>(/*this*/ IEnumerable<TSource> source)
        {
            if (source == null)
                throw new ArgumentNullException();

            foreach (TSource element in source)
                return true;
            return false;
        }


        public static bool Any<TSource>(/*this*/ IEnumerable<TSource> source, Func<TSource, bool> predicate)
        {
            if (source == null || predicate == null)
                throw new ArgumentNullException();

            foreach (TSource element in source)
                if (predicate(element))
                    return true;
            return false;
        }
        #endregion

        #region AsEnumerable
        public static IEnumerable<TSource> AsEnumerable<TSource>(/*this*/ IEnumerable<TSource> source)
        {
            return source;
        }
        #endregion

        #region Average
        public static double Average(/*this*/ IEnumerable<int> source)
        {
            if (source == null)
                throw new ArgumentNullException();

            long sum = 0;
            long counter = 0;
            foreach (int element in source)
            {
                sum += element;
                counter++;
            }

            if (counter == 0)
                throw new InvalidOperationException();
            else
                return (double)sum / (double)counter;
        }


        public static double? Average(/*this*/ IEnumerable<int?> source)
        {
            if (source == null)
                throw new ArgumentNullException();

            bool onlyNull = true;
            long sum = 0;
            long counter = 0;
            foreach (int? element in source)
            {
                if (element.HasValue)
                {
                    onlyNull = false;
                    sum += element.Value;
                    counter++;
                }
            }
            return (onlyNull ? null : (double?)sum / (double?)counter);
        }


        public static double Average(/*this*/ IEnumerable<long> source)
        {
            if (source == null)
                throw new ArgumentNullException();

            long sum = 0;
            long counter = 0;
            foreach (long element in source)
            {
                sum += element;
                counter++;
            }

            if (counter == 0)
                throw new InvalidOperationException();
            else
                return (double)sum / (double)counter;
        }


        public static double? Average(/*this*/ IEnumerable<long?> source)
        {
            if (source == null)
                throw new ArgumentNullException();

            bool onlyNull = true;
            long sum = 0;
            long counter = 0;
            foreach (long? element in source)
            {
                if (element.HasValue)
                {
                    onlyNull = false;
                    sum += element.Value;
                    counter++;
                }
            }
            return (onlyNull ? null : (double?)sum / (double?)counter);
        }


        public static double Average(/*this*/ IEnumerable<double> source)
        {
            if (source == null)
                throw new ArgumentNullException();

            double sum = 0;
            double counter = 0;
            foreach (double element in source)
            {
                sum += element;
                counter++;
            }

            if (counter == 0)
                throw new InvalidOperationException();
            else
                return sum / counter;
        }


        public static double? Average(/*this*/ IEnumerable<double?> source)
        {
            if (source == null)
                throw new ArgumentNullException();

            bool onlyNull = true;
            double sum = 0;
            double counter = 0;
            foreach (double? element in source)
            {
                if (element.HasValue)
                {
                    onlyNull = false;
                    sum += element.Value;
                    counter++;
                }
            }
            return (onlyNull ? null : (double?)(sum / counter));
        }


        public static decimal Average(/*this*/ IEnumerable<decimal> source)
        {
            if (source == null)
                throw new ArgumentNullException();

            decimal sum = 0;
            decimal counter = 0;
            foreach (decimal element in source)
            {
                sum += element;
                counter++;
            }

            if (counter == 0)
                throw new InvalidOperationException();
            else
                return sum / counter;
        }


        public static decimal? Average(/*this*/ IEnumerable<decimal?> source)
        {
            if (source == null)
                throw new ArgumentNullException();

            bool onlyNull = true;
            decimal sum = 0;
            decimal counter = 0;
            foreach (decimal? element in source)
            {
                if (element.HasValue)
                {
                    onlyNull = false;
                    sum += element.Value;
                    counter++;
                }
            }
            return (onlyNull ? null : (decimal?)(sum / counter));
        }


        public static double Average<TSource>(/*this*/ IEnumerable<TSource> source, Func<TSource, int> selector)
        {
            if (source == null || selector == null)
                throw new ArgumentNullException();

            long sum = 0;
            long counter = 0;
            foreach (TSource item in source)
            {
                sum += selector(item);
                counter++;
            }

            if (counter == 0)
                throw new InvalidOperationException();
            else
                return (double)sum / (double)counter;
        }


        public static double? Average<TSource>(/*this*/ IEnumerable<TSource> source, Func<TSource, int?> selector)
        {
            if (source == null || selector == null)
                throw new ArgumentNullException();

            bool onlyNull = true;
            long sum = 0;
            long counter = 0;
            foreach (TSource item in source)
            {
                int? element = selector(item);
                if (element.HasValue)
                {
                    onlyNull = false;
                    sum += element.Value;
                    counter++;
                }
            }
            return (onlyNull ? null : (double?)sum / (double?)counter);
        }


        public static double Average<TSource>(/*this*/ IEnumerable<TSource> source, Func<TSource, long> selector)
        {
            if (source == null || selector == null)
                throw new ArgumentNullException();

            long sum = 0;
            long counter = 0;
            foreach (TSource item in source)
            {
                sum += selector(item);
                counter++;
            }

            if (counter == 0)
                throw new InvalidOperationException();
            else
                return (double)sum / (double)counter;
        }


        public static double? Average<TSource>(/*this*/ IEnumerable<TSource> source, Func<TSource, long?> selector)
        {
            if (source == null || selector == null)
                throw new ArgumentNullException();

            bool onlyNull = true;
            long sum = 0;
            long counter = 0;
            foreach (TSource item in source)
            {
                long? element = selector(item);
                if (element.HasValue)
                {
                    onlyNull = false;
                    sum += element.Value;
                    counter++;
                }
            }
            return (onlyNull ? null : (double?)sum / (double?)counter);
        }


        public static double Average<TSource>( /*this*/ IEnumerable<TSource> source, Func<TSource, double> selector)
        {
            if (source == null || selector == null)
                throw new ArgumentNullException();

            double sum = 0;
            double counter = 0;
            foreach (TSource item in source)
            {
                sum += selector(item);
                counter++;
            }

            if (counter == 0)
                throw new InvalidOperationException();
            else
                return sum / counter;
        }


        public static double? Average<TSource>(/*this*/ IEnumerable<TSource> source, Func<TSource, double?> selector)
        {
            if (source == null || selector == null)
                throw new ArgumentNullException();

            bool onlyNull = true;
            double sum = 0;
            double counter = 0;
            foreach (TSource item in source)
            {
                double? element = selector(item);
                if (element.HasValue)
                {
                    onlyNull = false;
                    sum += element.Value;
                    counter++;
                }
            }
            return (onlyNull ? null : (double?)(sum / counter));
        }


        public static decimal Average<TSource>(/*this*/ IEnumerable<TSource> source, Func<TSource, decimal> selector)
        {
            if (source == null || selector == null)
                throw new ArgumentNullException();

            decimal sum = 0;
            decimal counter = 0;
            foreach (TSource item in source)
            {
                sum += selector(item);
                counter++;
            }

            if (counter == 0)
                throw new InvalidOperationException();
            else
                return sum / counter;
        }


        public static decimal? Average<TSource>(/*this*/ IEnumerable<TSource> source, Func<TSource, decimal?> selector)
        {
            if (source == null || selector == null)
                throw new ArgumentNullException();

            bool onlyNull = true;
            decimal sum = 0;
            decimal counter = 0;
            foreach (TSource item in source)
            {
                decimal? element = selector(item);
                if (element.HasValue)
                {
                    onlyNull = false;
                    sum += element.Value;
                    counter++;
                }
            }
            return (onlyNull ? null : (decimal?)(sum / counter));
        }
        #endregion

        #region Cast
        public static IEnumerable<TSource> Cast<TSource>(/*this*/ IEnumerable source)
        {
            if (source == null)
                throw new ArgumentNullException();

            foreach (object element in source)
                yield return (TSource)element;
        }
        #endregion

        #region Concat
        public static IEnumerable<TSource> Concat<TSource>(/*this*/ IEnumerable<TSource> first, IEnumerable<TSource> second)
        {
            if (first == null || second == null)
                throw new ArgumentNullException();

            foreach (TSource element in first)
                yield return element;
            foreach (TSource element in second)
                yield return element;
        }

        #endregion

        #region Contains

        public static bool Contains<TSource>(/*this*/ IEnumerable<TSource> source, TSource value)
        {
            if (source is ICollection<TSource>)
            {
                ICollection<TSource> collection = (ICollection<TSource>)source;
                return collection.Contains(value);
            }

            return Contains<TSource>(source, value, null);
        }


        public static bool Contains<TSource>(/*this*/ IEnumerable<TSource> source, TSource value, IEqualityComparer<TSource> comparer)
        {
            if (source == null)
                throw new ArgumentNullException("source");

            if (comparer == null)
                comparer = EqualityComparer<TSource>.Default;


            foreach (TSource e in source)
            {
                if (comparer.Equals(e, value))
                    return true;
            }

            return false;
        }
        #endregion

        #region Count
        public static int Count<TSource>(/*this*/ IEnumerable<TSource> source)
        {
            if (source == null)
                throw new ArgumentNullException();

            if (source is ICollection<TSource>)
                return ((ICollection<TSource>)source).Count;
            else
            {
                int counter = 0;
                foreach (TSource element in source)
                    counter++;
                return counter;
            }
        }


        public static int Count<TSource>(/*this*/ IEnumerable<TSource> source, Func<TSource, bool> selector)
        {
            if (source == null || selector == null)
                throw new ArgumentNullException();

            int counter = 0;
            foreach (TSource element in source)
                if (selector(element))
                    counter++;

            return counter;
        }
        #endregion

        #region DefaultIfEmpty

        public static IEnumerable<TSource> DefaultIfEmpty<TSource>(/*this*/ IEnumerable<TSource> source)
        {
            if (source == null)
                throw new ArgumentNullException();

            bool noYield = true;
            foreach (TSource item in source)
            {
                noYield = false;
                yield return item;
            }

            if (noYield)
                yield return default(TSource);
        }


        public static IEnumerable<TSource> DefaultIfEmpty<TSource>(/*this*/ IEnumerable<TSource> source, TSource defaultValue)
        {
            if (source == null)
                throw new ArgumentNullException();

            bool noYield = true;
            foreach (TSource item in source)
            {
                noYield = false;
                yield return item;
            }

            if (noYield)
                yield return defaultValue;
        }

        #endregion

        #region Distinct

        public static IEnumerable<TSource> Distinct<TSource>(/*this*/ IEnumerable<TSource> source)
        {
            return Distinct<TSource>(source, null);
        }

        public static IEnumerable<TSource> Distinct<TSource>(/*this*/ IEnumerable<TSource> source, IEqualityComparer<TSource> comparer)
        {
            if (source == null)
                throw new ArgumentNullException();

            if (comparer == null)
                comparer = EqualityComparer<TSource>.Default;

            List<TSource> items = new List<TSource>();
            foreach (TSource element in source)
            {
                if (!Contains (items, element, comparer))
                {
                    items.Add(element);
                    yield return element;
                }
            }
        }
        #endregion

        #region ElementAt

        public static TSource ElementAt<TSource>(/*this*/ IEnumerable<TSource> source, int index)
        {
            if (source == null)
                throw new ArgumentNullException();
            if (index < 0)
                throw new ArgumentOutOfRangeException();

            if (source is IList<TSource>)
                return ((IList<TSource>)source)[index];
            else
            {
                int counter = 0;
                foreach (TSource element in source)
                {
                    if (counter == index)
                        return element;
                    counter++;
                }
                throw new ArgumentOutOfRangeException();
            }
        }

        #endregion

        #region ElementAtOrDefault

        public static TSource ElementAtOrDefault<TSource>(/*this*/ IEnumerable<TSource> source, int index)
        {
            if (source == null)
                throw new ArgumentNullException();
            if (index < 0)
                return default(TSource);

            if (source is IList<TSource>)
            {
                if (((IList<TSource>)source).Count >= index)
                    return default(TSource);
                else
                    return ((IList<TSource>)source)[index];
            }
            else
            {
                int counter = 0;
                foreach (TSource element in source)
                {
                    if (counter == index)
                        return element;
                    counter++;
                }
                return default(TSource);
            }
        }

        #endregion

        #region Empty
        public static IEnumerable<TResult> Empty<TResult>()
        {
            return new List<TResult>();
        }
        #endregion

        #region Except

        public static IEnumerable<TSource> Except<TSource>(/*this*/ IEnumerable<TSource> first, IEnumerable<TSource> second)
        {
            return Except(first, second, null);
        }

        public static IEnumerable<TSource> Except<TSource>(/*this*/ IEnumerable<TSource> first, IEnumerable<TSource> second, IEqualityComparer<TSource> comparer)
        {
            if (first == null || second == null)
                throw new ArgumentNullException();

            if (comparer == null)
                comparer = EqualityComparer<TSource>.Default;

            List<TSource> items = new List<TSource>(Distinct(first));
            foreach (TSource element in second)
            {
                int index = IndexOf(items, element, comparer);
                if (index == -1)
                    items.Add(element);
                else
                    items.RemoveAt(index);
            }
            foreach (TSource item in items)
                yield return item;
        }

        #endregion

        #region First

        public static TSource First<TSource>(/*this*/ IEnumerable<TSource> source)
        {
            if (source == null)
                throw new ArgumentNullException();

            foreach (TSource element in source)
                return element;

            throw new InvalidOperationException();
        }


        public static TSource First<TSource>(/*this*/ IEnumerable<TSource> source, Func<TSource, bool> predicate)
        {
            if (source == null || predicate == null)
                throw new ArgumentNullException();

            foreach (TSource element in source)
            {
                if (predicate(element))
                    return element;
            }

            throw new InvalidOperationException();
        }

        #endregion

        #region FirstOrDefault

        public static T FirstOrDefault<T>(/*this*/ IEnumerable<T> source)
        {
            if (source == null)
                throw new ArgumentNullException();

            foreach (T element in source)
                return element;

            return default(T);
        }


        public static T FirstOrDefault<T>(/*this*/ IEnumerable<T> source, Func<T, bool> predicate)
        {
            if (source == null || predicate == null)
                throw new ArgumentNullException();

            foreach (T element in source)
            {
                if (predicate(element))
                    return element;
            }

            return default(T);
        }

        #endregion

        #region GroupBy

        private static List<T> ContainsGroup<K, T>(
                Dictionary<K, List<T>> items, K key, IEqualityComparer<K> comparer)
        {
            IEqualityComparer<K> comparerInUse = (comparer ?? EqualityComparer<K>.Default);
            foreach (KeyValuePair<K, List<T>> value in items)
            {
                if (comparerInUse.Equals(value.Key, key))
                    return value.Value;
            }
            return null;
        }


        public static IEnumerable<IGrouping<TKey, TSource>> GroupBy<TSource, TKey>(/*this*/ IEnumerable<TSource> source, 
            Func<TSource, TKey> keySelector)
        {
            return GroupBy<TSource, TKey>(source, keySelector, null);
        }


        public static IEnumerable<IGrouping<TKey, TSource>> GroupBy<TSource, TKey>(/*this*/ IEnumerable<TSource> source,
            Func<TSource, TKey> keySelector, IEqualityComparer<TKey> comparer)
        {
            if (source == null || keySelector == null)
                throw new ArgumentNullException();

            Dictionary<TKey, List<TSource>> groups = new Dictionary<TKey, List<TSource>>();
            List<TSource> nullList = new List<TSource>();
            int counter = 0;
            int nullCounter = -1;

            foreach (TSource element in source)
            {
                TKey key = keySelector(element);
                if (key == null)
                {
                    nullList.Add(element);
                    if (nullCounter == -1)
                    {
                        nullCounter = counter;
                        counter++;
                    }
                }
                else
                {
                    List<TSource> group = ContainsGroup<TKey, TSource>(groups, key, comparer);
                    if (group == null)
                    {
                        group = new List<TSource>();
                        groups.Add(key, group);
                        counter++;
                    }
                    group.Add(element);
                }
            }

            counter = 0;
            foreach (KeyValuePair<TKey, List<TSource>> group in groups)
            {
                if (counter == nullCounter)
                {
                    Grouping<TKey, TSource> nullGroup = new Grouping<TKey, TSource>(default(TKey), nullList);
                    yield return nullGroup;
                    counter++;
                }
                Grouping<TKey, TSource> grouping = new Grouping<TKey, TSource>(group.Key, group.Value);
                yield return grouping;
                counter++;
            }
        }


        public static IEnumerable<IGrouping<TKey, TElement>> GroupBy<TSource, TKey, TElement>(/*this*/ IEnumerable<TSource> source,
            Func<TSource, TKey> keySelector, Func<TSource, TElement> elementSelector)
        {
            return GroupBy<TSource, TKey, TElement>(source, keySelector, elementSelector, null);
        }


        public static IEnumerable<IGrouping<TKey, TElement>> GroupBy<TSource, TKey, TElement>(/*this*/ IEnumerable<TSource> source,
            Func<TSource, TKey> keySelector, Func<TSource, TElement> elementSelector, IEqualityComparer<TKey> comparer)
        {
            if (source == null || keySelector == null || elementSelector == null)
                throw new ArgumentNullException();

            Dictionary<TKey, List<TElement>> groups = new Dictionary<TKey, List<TElement>>();
            List<TElement> nullList = new List<TElement>();
            int counter = 0;
            int nullCounter = -1;

            foreach (TSource item in source)
            {
                TKey key = keySelector(item);
                TElement element = elementSelector(item);
                if (key == null)
                {
                    nullList.Add(element);
                    if (nullCounter == -1)
                    {
                        nullCounter = counter;
                        counter++;
                    }
                }
                else
                {
                    List<TElement> group = ContainsGroup<TKey, TElement>(groups, key, comparer);
                    if (group == null)
                    {
                        group = new List<TElement>();
                        groups.Add(key, group);
                        counter++;
                    }
                    group.Add(element);
                }
            }

            counter = 0;
            foreach (KeyValuePair<TKey, List<TElement>> group in groups)
            {
                if (counter == nullCounter)
                {
                    Grouping<TKey, TElement> nullGroup = new Grouping<TKey, TElement>(default(TKey), nullList);
                    yield return nullGroup;
                    counter++;
                }
                Grouping<TKey, TElement> grouping = new Grouping<TKey, TElement>(group.Key, group.Value);
                yield return grouping;
                counter++;
            }
        }

        #endregion

        # region GroupJoin

        public static IEnumerable<TResult> GroupJoin<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)
        {
            return GroupJoin(outer, inner, outerKeySelector, innerKeySelector, resultSelector, null);
        }

        public static IEnumerable<TResult> GroupJoin<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)
        {
            if (outer == null || inner == null || outerKeySelector == null ||
                innerKeySelector == null || resultSelector == null)
                throw new ArgumentNullException();

            if (comparer == null)
                comparer = EqualityComparer<TKey>.Default;

            Lookup<TKey, TInner> innerKeys = ToLookup<TInner, TKey>(inner, innerKeySelector, comparer);
            /*Dictionary<K, List<U>> innerKeys = new Dictionary<K, List<U>> ();
            foreach (U element in inner)
            {
                    K innerKey = innerKeySelector (element);
                    if (!innerKeys.ContainsKey (innerKey))
                            innerKeys.Add (innerKey, new List<U> ());
                    innerKeys[innerKey].Add (element);
            }*/

            foreach (TOuter element in outer)
            {
                TKey outerKey = outerKeySelector(element);
                if (innerKeys.Contains(outerKey))
                    yield return resultSelector(element, innerKeys[outerKey]);
            }
        }

        #endregion

        #region Intersect


        public static IEnumerable<TSource> Intersect<TSource>(/*this*/ IEnumerable<TSource> first, IEnumerable<TSource> second)
        {
            if (first == null || second == null)
                throw new ArgumentNullException();

            List<TSource> items = new List<TSource>(Distinct(first));
            bool[] marked = new bool[items.Count];
            for (int i = 0; i < marked.Length; i++)
                marked[i] = false;

            foreach (TSource element in second)
            {
                int index = IndexOf(items, element);
                if (index != -1)
                    marked[index] = true;
            }
            for (int i = 0; i < marked.Length; i++)
            {
                if (marked[i])
                    yield return items[i];
            }
        }

        #endregion

        # region Join

        public static IEnumerable<TResult> Join<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)
        {
            if (outer == null || inner == null || outerKeySelector == null ||
                    innerKeySelector == null || resultSelector == null)
                throw new ArgumentNullException();

            if (comparer == null)
                comparer = EqualityComparer<TKey>.Default;

            Lookup<TKey, TInner> innerKeys = ToLookup<TInner, TKey>(inner, innerKeySelector, comparer);
            /*Dictionary<K, List<U>> innerKeys = new Dictionary<K, List<U>> ();
            foreach (U element in inner)
            {
                    K innerKey = innerKeySelector (element);
                    if (!innerKeys.ContainsKey (innerKey))
                            innerKeys.Add (innerKey, new List<U> ());
                    innerKeys[innerKey].Add (element);
            }*/

            foreach (TOuter element in outer)
            {
                TKey outerKey = outerKeySelector(element);
                if (innerKeys.Contains(outerKey))
                {
                    foreach (TInner innerElement in innerKeys[outerKey])
                        yield return resultSelector(element, innerElement);
                }
            }
        }

        public static IEnumerable<TResult> Join<TOuter, TInner, TKey, TResult>(/*this*/ IEnumerable<TOuter> outer,
            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);
        }
        # endregion

        #region Last

        public static TSource Last<TSource>(/*this*/ IEnumerable<TSource> source)
        {
            if (source == null)
                throw new ArgumentNullException();

            bool noElements = true;
            TSource lastElement = default(TSource);
            foreach (TSource element in source)
            {
                if (noElements) noElements = false;
                lastElement = element;
            }

            if (!noElements)
                return lastElement;
            else
                throw new InvalidOperationException();
        }

        public static TSource Last<TSource>(/*this*/ IEnumerable<TSource> source,
                Func<TSource, bool> predicate)
        {
            if (source == null || predicate == null)
                throw new ArgumentNullException();

            bool noElements = true;
            TSource lastElement = default(TSource);
            foreach (TSource element in source)
            {
                if (predicate(element))
                {
                    if (noElements) noElements = false;
                    lastElement = element;
                }
            }

            if (!noElements)
                return lastElement;
            else
                throw new InvalidOperationException();
        }

        #endregion

        #region LastOrDefault

        public static TSource LastOrDefault<TSource>(/*this*/ IEnumerable<TSource> source)
        {
            if (source == null)
                throw new ArgumentNullException();

            TSource lastElement = default(TSource);
            foreach (TSource element in source)
                lastElement = element;

            return lastElement;
        }

        public static TSource LastOrDefault<TSource>(/*this*/ IEnumerable<TSource> source,
            Func<TSource, bool> predicate)
        {
            if (source == null || predicate == null)
                throw new ArgumentNullException();

            TSource lastElement = default(TSource);
            foreach (TSource element in source)
            {
                if (predicate(element))
                    lastElement = element;
            }

            return lastElement;
        }

        #endregion

        #region LongCount
        public static long LongCount<TSource>(/*this*/ IEnumerable<TSource> source)
        {
            if (source == null)
                throw new ArgumentNullException();

            long counter = 0;
            foreach (TSource element in source)
                counter++;
            return counter;
        }


        public static long LongCount<TSource>(/*this*/ IEnumerable<TSource> source, Func<TSource, bool> selector)
        {
            if (source == null || selector == null)
                throw new ArgumentNullException();

            long counter = 0;
            foreach (TSource element in source)
                if (selector(element))
                    counter++;

            return counter;
        }

        #endregion

        #region Max

        public static int Max(/*this*/ IEnumerable<int> source)
        {
            if (source == null)
                throw new ArgumentNullException();

            int maximum = int.MinValue;
            int counter = 0;
            foreach (int element in source)
            {
                if (element > maximum)
                    maximum = element;
                counter++;
            }

            if (counter == 0)
                throw new InvalidOperationException();
            else
                return maximum;
        }


        public static int? Max(/*this*/ IEnumerable<int?> source)
        {
            if (source == null)
                throw new ArgumentNullException();

            bool onlyNull = true;
            int? maximum = int.MinValue;
            foreach (int? element in source)
            {
                if (element.HasValue)
                {
                    onlyNull = false;
                    if (element > maximum)
                        maximum = element;
                }
            }
            return (onlyNull ? null : maximum);
        }


        public static long Max(/*this*/ IEnumerable<long> source)
        {
            if (source == null)
                throw new ArgumentNullException();

            long maximum = long.MinValue;
            int counter = 0;
            foreach (long element in source)
            {
                if (element > maximum)
                    maximum = element;
                counter++;
            }

            if (counter == 0)
                throw new InvalidOperationException();
            else
                return maximum;
        }


        public static long? Max(/*this*/ IEnumerable<long?> source)
        {
            if (source == null)
                throw new ArgumentNullException();

            bool onlyNull = true;
            long? maximum = long.MinValue;
            foreach (long? element in source)
            {
                if (element.HasValue)
                {
                    onlyNull = false;
                    if (element > maximum)
                        maximum = element;
                }
            }
            return (onlyNull ? null : maximum);
        }


        public static double Max(/*this*/ IEnumerable<double> source)
        {
            if (source == null)
                throw new ArgumentNullException();

            double maximum = double.MinValue;
            int counter = 0;
            foreach (double element in source)
            {
                if (element > maximum)
                    maximum = element;
                counter++;
            }

            if (counter == 0)
                throw new InvalidOperationException();
            else
                return maximum;
        }


        public static double? Max(/*this*/ IEnumerable<double?> source)
        {
            if (source == null)
                throw new ArgumentNullException();

            bool onlyNull = true;
            double? maximum = double.MinValue;
            foreach (double? element in source)
            {
                if (element.HasValue)
                {
                    onlyNull = false;
                    if (element > maximum)
                        maximum = element;
                }
            }
            return (onlyNull ? null : maximum);
        }


        public static decimal Max(/*this*/ IEnumerable<decimal> source)
        {
            if (source == null)
                throw new ArgumentNullException();

            decimal maximum = decimal.MinValue;
            int counter = 0;
            foreach (decimal element in source)
            {
                if (element > maximum)
                    maximum = element;
                counter++;
            }

            if (counter == 0)
                throw new InvalidOperationException();
            else
                return maximum;
        }


        public static decimal? Max(/*this*/ IEnumerable<decimal?> source)
        {
            if (source == null)
                throw new ArgumentNullException();

            bool onlyNull = true;
            decimal? maximum = decimal.MinValue;
            foreach (decimal? element in source)
            {
                if (element.HasValue)
                {
                    onlyNull = false;
                    if (element > maximum)
                        maximum = element;
                }
            }
            return (onlyNull ? null : maximum);
        }


        public static T Max<T>(/*this*/ IEnumerable<T> source)
        {
            if (source == null)
                throw new ArgumentNullException();

            bool notAssigned = true;
            T maximum = default(T);
            int counter = 0;
            foreach (T element in source)
            {
                if (notAssigned)
                {
                    maximum = element;
                    notAssigned = false;
                }
                else
                {
                    int comparison;
                    if (element is IComparable<T>)
                        comparison = ((IComparable<T>)element).CompareTo(maximum);
                    else if (element is System.IComparable)
                        comparison = ((System.IComparable)element).CompareTo(maximum);
                    else
                        throw new ArgumentNullException();

                    if (comparison > 0)
                        maximum = element;
                }
                counter++;
            }

            if (counter == 0)
                throw new InvalidOperationException();
            else
                return maximum;
        }


        public static int Max<T>(/*this*/ IEnumerable<T> source,
                Func<T, int> selector)
        {
            if (source == null || selector == null)
                throw new ArgumentNullException();

            int maximum = int.MinValue;
            int counter = 0;
            foreach (T item in source)
            {
                int element = selector(item);
                if (element > maximum)
                    maximum = element;
                counter++;
            }

            if (counter == 0)
                throw new InvalidOperationException();
            else
                return maximum;
        }


        public static int? Max<T>(/*this*/ IEnumerable<T> source,
                Func<T, int?> selector)
        {
            if (source == null || selector == null)
                throw new ArgumentNullException();

            bool onlyNull = true;
            int? maximum = int.MinValue;
            foreach (T item in source)
            {
                int? element = selector(item);
                if (element.HasValue)
                {
                    onlyNull = false;
                    if (element > maximum)
                        maximum = element;
                }
            }
            return (onlyNull ? null : maximum);
        }


        public static long Max<TSource>(/*this*/ IEnumerable<TSource> source,
            Func<TSource, long> selector)
        {
            if (source == null || selector == null)
                throw new ArgumentNullException();

            long maximum = long.MinValue;
            int counter = 0;
            foreach (TSource item in source)
            {
                long element = selector(item);
                if (element > maximum)
                    maximum = element;
                counter++;
            }

            if (counter == 0)
                throw new InvalidOperationException();
            else
                return maximum;
        }


        public static long? Max<TSource>(/*this*/ IEnumerable<TSource> source,
            Func<TSource, long?> selector)
        {
            if (source == null || selector == null)
                throw new ArgumentNullException();

            bool onlyNull = true;
            long? maximum = long.MinValue;
            foreach (TSource item in source)
            {
                long? element = selector(item);
                if (element.HasValue)
                {
                    onlyNull = false;
                    if (element > maximum)
                        maximum = element;
                }
            }
            return (onlyNull ? null : maximum);
        }


        public static double Max<TSource>(/*this*/ IEnumerable<TSource> source,
            Func<TSource, double> selector)
        {
            if (source == null || selector == null)
                throw new ArgumentNullException();

            double maximum = double.MinValue;
            int counter = 0;
            foreach (TSource item in source)
            {
                double element = selector(item);
                if (element > maximum)
                    maximum = element;
                counter++;
            }

            if (counter == 0)
                throw new InvalidOperationException();
            else
                return maximum;
        }


        public static double? Max<TSource>(/*this*/ IEnumerable<TSource> source,
            Func<TSource, double?> selector)
        {
            if (source == null || selector == null)
                throw new ArgumentNullException();

            bool onlyNull = true;
            double? maximum = double.MinValue;
            foreach (TSource item in source)
            {
                double? element = selector(item);
                if (element.HasValue)
                {
                    onlyNull = false;
                    if (element > maximum)
                        maximum = element;
                }
            }
            return (onlyNull ? null : maximum);
        }


        public static decimal Max<TSource>(/*this*/ IEnumerable<TSource> source,
            Func<TSource, decimal> selector)
        {
            if (source == null || selector == null)
                throw new ArgumentNullException();

            decimal maximum = decimal.MinValue;
            int counter = 0;
            foreach (TSource item in source)
            {
                decimal element = selector(item);
                if (element > maximum)
                    maximum = element;
                counter++;
            }

            if (counter == 0)
                throw new InvalidOperationException();
            else
                return maximum;
        }


        public static decimal? Max<TSource>(/*this*/ IEnumerable<TSource> source,
            Func<TSource, decimal?> selector)
        {
            if (source == null || selector == null)
                throw new ArgumentNullException();

            bool onlyNull = true;
            decimal? maximum = decimal.MinValue;
            foreach (TSource item in source)
            {
                decimal? element = selector(item);
                if (element.HasValue)
                {
                    onlyNull = false;
                    if (element > maximum)
                        maximum = element;
                }
            }
            return (onlyNull ? null : maximum);
        }


        public static TResult Max<TSource, TResult>(/*this*/ IEnumerable<TSource> source,
                Func<TSource, TResult> selector)
        {
            if (source == null || selector == null)
                throw new ArgumentNullException();

            bool notAssigned = true;
            TResult maximum = default(TResult);
            int counter = 0;
            foreach (TSource item in source)
            {
                TResult element = selector(item);
                if (notAssigned)
                {
                    maximum = element;
                    notAssigned = false;
                }
                else
                {
                    int comparison;
                    if (element is IComparable<TResult>)
                        comparison = ((IComparable<TResult>)element).CompareTo(maximum);
                    else if (element is System.IComparable)
                        comparison = ((System.IComparable)element).CompareTo(maximum);
                    else
                        throw new ArgumentNullException();

                    if (comparison > 0)
                        maximum = element;
                }
                counter++;
            }

            if (counter == 0)
                throw new InvalidOperationException();
            else
                return maximum;
        }

        #endregion

        #region Min

        public static int Min(/*this*/ IEnumerable<int> source)
        {
            if (source == null)
                throw new ArgumentNullException();

            int minimum = int.MaxValue;
            int counter = 0;
            foreach (int element in source)
            {
                if (element < minimum)
                    minimum = element;
                counter++;
            }

            if (counter == 0)
                throw new InvalidOperationException();
            else
                return minimum;
        }


        public static int? Min(/*this*/ IEnumerable<int?> source)
        {
            if (source == null)
                throw new ArgumentNullException();

            bool onlyNull = true;
            int? minimum = int.MaxValue;
            foreach (int? element in source)
            {
                if (element.HasValue)
                {
                    onlyNull = false;
                    if (element < minimum)
                        minimum = element;
                }
            }
            return (onlyNull ? null : minimum);
        }

        public static long Min(/*this*/ IEnumerable<long> source)
        {
            if (source == null)
                throw new ArgumentNullException();

            long minimum = long.MaxValue;
            int counter = 0;
            foreach (long element in source)
            {
                if (element < minimum)
                    minimum = element;
                counter++;
            }

            if (counter == 0)
                throw new InvalidOperationException();
            else
                return minimum;
        }


        public static long? Min(/*this*/ IEnumerable<long?> source)
        {
            if (source == null)
                throw new ArgumentNullException();

            bool onlyNull = true;
            long? minimum = long.MaxValue;
            foreach (long? element in source)
            {
                if (element.HasValue)
                {
                    onlyNull = false;
                    if (element < minimum)
                        minimum = element;
                }
            }
            return (onlyNull ? null : minimum);
        }


        public static double Min(/*this*/ IEnumerable<double> source)
        {
            if (source == null)
                throw new ArgumentNullException();

            double minimum = double.MaxValue;
            int counter = 0;
            foreach (double element in source)
            {
                if (element < minimum)
                    minimum = element;
                counter++;
            }

            if (counter == 0)
                throw new InvalidOperationException();
            else
                return minimum;
        }


        public static double? Min(/*this*/ IEnumerable<double?> source)
        {
            if (source == null)
                throw new ArgumentNullException();

            bool onlyNull = true;
            double? minimum = double.MaxValue;
            foreach (double? element in source)
            {
                if (element.HasValue)
                {
                    onlyNull = false;
                    if (element < minimum)
                        minimum = element;
                }
            }
            return (onlyNull ? null : minimum);
        }


        public static decimal Min(/*this*/ IEnumerable<decimal> source)
        {
            if (source == null)
                throw new ArgumentNullException();

            decimal minimum = decimal.MaxValue;
            int counter = 0;
            foreach (decimal element in source)
            {
                if (element < minimum)
                    minimum = element;
                counter++;
            }

            if (counter == 0)
                throw new InvalidOperationException();
            else
                return minimum;
        }


        public static decimal? Min(/*this*/ IEnumerable<decimal?> source)
        {
            if (source == null)
                throw new ArgumentNullException();

            bool onlyNull = true;
            decimal? minimum = decimal.MaxValue;
            foreach (decimal? element in source)
            {
                if (element.HasValue)
                {
                    onlyNull = false;
                    if (element < minimum)
                        minimum = element;
                }
            }
            return (onlyNull ? null : minimum);
        }


        public static TSource Min<TSource>(/*this*/ IEnumerable<TSource> source)
        {
            if (source == null)
                throw new ArgumentNullException();

            bool notAssigned = true;
            TSource minimum = default(TSource);
            int counter = 0;
            foreach (TSource element in source)
            {
                if (notAssigned)
                {
                    minimum = element;
                    notAssigned = false;
                }
                else
                {
                    int comparison;
                    if (element is IComparable<TSource>)
                        comparison = ((IComparable<TSource>)element).CompareTo(minimum);
                    else if (element is System.IComparable)
                        comparison = ((System.IComparable)element).CompareTo(minimum);
                    else
                        throw new ArgumentNullException();

                    if (comparison < 0)
                        minimum = element;
                }
                counter++;
            }

            if (counter == 0)
                throw new InvalidOperationException();
            else
                return minimum;
        }


        public static int Min<TSource>(/*this*/ IEnumerable<TSource> source,
            Func<TSource, int> selector)
        {
            if (source == null || selector == null)
                throw new ArgumentNullException();

            int minimum = int.MaxValue;
            int counter = 0;
            foreach (TSource item in source)
            {
                int element = selector(item);
                if (element < minimum)
                    minimum = element;
                counter++;
            }

            if (counter == 0)
                throw new InvalidOperationException();
            else
                return minimum;
        }


        public static int? Min<TSource>(/*this*/ IEnumerable<TSource> source,
                Func<TSource, int?> selector)
        {
            if (source == null || selector == null)
                throw new ArgumentNullException();

            bool onlyNull = true;
            int? minimum = int.MaxValue;
            foreach (TSource item in source)
            {
                int? element = selector(item);
                if (element.HasValue)
                {
                    onlyNull = false;
                    if (element < minimum)
                        minimum = element;
                }
            }
            return (onlyNull ? null : minimum);
        }


        public static long Min<TSource>(/*this*/ IEnumerable<TSource> source,
                Func<TSource, long> selector)
        {
            if (source == null || selector == null)
                throw new ArgumentNullException();

            long minimum = long.MaxValue;
            int counter = 0;
            foreach (TSource item in source)
            {
                long element = selector(item);
                if (element < minimum)
                    minimum = element;
                counter++;
            }

            if (counter == 0)
                throw new InvalidOperationException();
            else
                return minimum;
        }


        public static long? Min<TSource>(/*this*/ IEnumerable<TSource> source,
                Func<TSource, long?> selector)
        {
            if (source == null || selector == null)
                throw new ArgumentNullException();

            bool onlyNull = true;
            long? minimum = long.MaxValue;
            foreach (TSource item in source)
            {
                long? element = selector(item);
                if (element.HasValue)
                {
                    onlyNull = false;
                    if (element < minimum)
                        minimum = element;
                }
            }
            return (onlyNull ? null : minimum);
        }


        public static double Min<TSource>(/*this*/ IEnumerable<TSource> source,
            Func<TSource, double> selector)
        {
            if (source == null || selector == null)
                throw new ArgumentNullException();

            double minimum = double.MaxValue;
            int counter = 0;
            foreach (TSource item in source)
            {
                double element = selector(item);
                if (element < minimum)
                    minimum = element;
                counter++;
            }

            if (counter == 0)
                throw new InvalidOperationException();
            else
                return minimum;
        }


        public static double? Min<TSource>(/*this*/ IEnumerable<TSource> source,
                Func<TSource, double?> selector)
        {
            if (source == null || selector == null)
                throw new ArgumentNullException();

            bool onlyNull = true;
            double? minimum = double.MaxValue;
            foreach (TSource item in source)
            {
                double? element = selector(item);
                if (element.HasValue)
                {
                    onlyNull = false;
                    if (element < minimum)
                        minimum = element;
                }
            }
            return (onlyNull ? null : minimum);
        }


        public static decimal Min<TSource>(/*this*/ IEnumerable<TSource> source,
                Func<TSource, decimal> selector)
        {
            if (source == null || selector == null)
                throw new ArgumentNullException();

            decimal minimum = decimal.MaxValue;
            int counter = 0;
            foreach (TSource item in source)
            {
                decimal element = selector(item);
                if (element < minimum)
                    minimum = element;
                counter++;
            }

            if (counter == 0)
                throw new InvalidOperationException();
            else
                return minimum;
        }


        public static decimal? Min<TSource>(/*this*/ IEnumerable<TSource> source,
                Func<TSource, decimal?> selector)
        {
            if (source == null || selector == null)
                throw new ArgumentNullException();

            bool onlyNull = true;
            decimal? minimum = decimal.MaxValue;
            foreach (TSource item in source)
            {
                decimal? element = selector(item);
                if (element.HasValue)
                {
                    onlyNull = false;
                    if (element < minimum)
                        minimum = element;
                }
            }
            return (onlyNull ? null : minimum);
        }


        public static TResult Min<TSource, TResult>(/*this*/ IEnumerable<TSource> source,
                Func<TSource, TResult> selector)
        {
            if (source == null || selector == null)
                throw new ArgumentNullException();

            bool notAssigned = true;
            TResult minimum = default(TResult);
            int counter = 0;
            foreach (TSource item in source)
            {
                TResult element = selector(item);
                if (notAssigned)
                {
                    minimum = element;
                    notAssigned = false;
                }
                else
                {
                    int comparison;
                    if (element is IComparable<TResult>)
                        comparison = ((IComparable<TResult>)element).CompareTo(minimum);
                    else if (element is System.IComparable)
                        comparison = ((System.IComparable)element).CompareTo(minimum);
                    else
                        throw new ArgumentNullException();

                    if (comparison < 0)
                        minimum = element;
                }
                counter++;
            }

            if (counter == 0)
                throw new InvalidOperationException();
            else
                return minimum;
        }

        #endregion

        #region OfType

        public static IEnumerable<TSource> OfType<TSource>(/*this*/ IEnumerable source)
        {
            if (source == null)
                throw new ArgumentNullException();

            foreach (object element in source)
                if (element is TSource)
                    yield return (TSource)element;
        }

        #endregion

        #region OrderBy

        public static OrderedSequence<TSource> OrderBy<TSource, TKey>(/*this*/ IEnumerable<TSource> source,
                Func<TSource, TKey> keySelector)
        {
            return OrderBy<TSource, TKey>(source, keySelector, null);
        }


        public static OrderedSequence<TSource> OrderBy<TSource, TKey>(/*this*/ IEnumerable<TSource> source,
                Func<TSource, TKey> keySelector,
                IComparer<TKey> comparer)
        {
            if (source == null || keySelector == null)
                throw new ArgumentNullException();

            return new InternalOrderedSequence<TSource, TKey>(
                    source, keySelector, (comparer ?? Comparer<TKey>.Default), false, null);
        }

        #endregion

        #region OrderByDescending

        public static OrderedSequence<TSource> OrderByDescending<TSource, TKey>(/*this*/ IEnumerable<TSource> source,
                Func<TSource, TKey> keySelector)
        {
            return OrderByDescending<TSource, TKey>(source, keySelector, null);
        }


        public static OrderedSequence<TSource> OrderByDescending<TSource, TKey>(/*this*/ IEnumerable<TSource> source,
                Func<TSource, TKey> keySelector, IComparer<TKey> comparer)
        {
            if (source == null || keySelector == null)
                throw new ArgumentNullException();

            return new InternalOrderedSequence<TSource, TKey>(
                    source, keySelector, (comparer ?? Comparer<TKey>.Default), true, null);
        }

        #endregion

        #region Range

        public static IEnumerable<int> Range(int start, int count)
        {
            if (count < 0 || (start + count - 1) > int.MaxValue)
                throw new ArgumentOutOfRangeException();

            for (int i = start; i < (start + count - 1); i++)
                yield return i;
        }

        #endregion

        #region Repeat

        public static IEnumerable<TResult> Repeat<TResult>(TResult element, int count)
        {
            if (count < 0)
                throw new ArgumentOutOfRangeException();

            for (int i = 0; i < count; i++)
                yield return element;
        }

        #endregion


        #region Reverse

        public static IEnumerable<TSource> Reverse<TSource>(/*this*/ IEnumerable<TSource> source)
        {
            if (source == null)
                throw new ArgumentNullException();

            List<TSource> list = new List<TSource>(source);
            list.Reverse();
            return list;
        }

        #endregion

        #region Select

        public static IEnumerable<TResult> Select<TSource, TResult>(/*this*/ IEnumerable<TSource> source,
                Func<TSource, TResult> selector)
        {
            if (source == null || selector == null)
                throw new ArgumentNullException();

            foreach (TSource element in source)
                yield return selector(element);
        }


        public static IEnumerable<TResult> Select<TSource, TResult>(/*this*/ IEnumerable<TSource> source,
                Func<TSource, int, TResult> selector)
        {
            if (source == null || selector == null)
                throw new ArgumentNullException();

            int counter = 0;
            foreach (TSource element in source)
            {
                yield return selector(element, counter);
                counter++;
            }
        }

        #endregion

        #region SelectMany

        public static IEnumerable<TResult> SelectMany<TSource, TResult>(/*this*/ IEnumerable<TSource> source,
                Func<TSource, IEnumerable<TResult>> selector)
        {
            if (source == null || selector == null)
                throw new ArgumentNullException();

            foreach (TSource element in source)
                foreach (TResult item in selector(element))
                    yield return item;
        }


        public static IEnumerable<TResult> SelectMany<TSource, TResult>(/*this*/ IEnumerable<TSource> source,
                Func<TSource, int, IEnumerable<TResult>> selector)
        {
            if (source == null || selector == null)
                throw new ArgumentNullException();

            int counter = 0;
            foreach (TSource element in source)
            {
                foreach (TResult item in selector(element, counter))
                    yield return item;
                counter++;
            }
        }

        #endregion

        #region Single

        public static TSource Single<TSource>(/*this*/ IEnumerable<TSource> source)
        {
            if (source == null)
                throw new ArgumentNullException();

            bool otherElement = false;
            TSource singleElement = default(TSource);
            foreach (TSource element in source)
            {
                if (otherElement) throw new InvalidOperationException();
                if (!otherElement) otherElement = true;
                singleElement = element;
            }

            if (otherElement)
                return singleElement;
            else
                throw new InvalidOperationException();
        }


        public static TSource Single<TSource>(/*this*/ IEnumerable<TSource> source,
                Func<TSource, bool> predicate)
        {
            if (source == null || predicate == null)
                throw new ArgumentNullException();

            bool otherElement = false;
            TSource singleElement = default(TSource);
            foreach (TSource element in source)
            {
                if (predicate(element))
                {
                    if (otherElement) throw new InvalidOperationException();
                    if (!otherElement) otherElement = true;
                    singleElement = element;
                }
            }

            if (otherElement)
                return singleElement;
            else
                throw new InvalidOperationException();
        }

        #endregion

        #region SingleOrDefault

        public static TSource SingleOrDefault<TSource>(/*this*/ IEnumerable<TSource> source)
        {
            if (source == null)
                throw new ArgumentNullException();

            bool otherElement = false;
            TSource singleElement = default(TSource);
            foreach (TSource element in source)
            {
                if (otherElement) throw new InvalidOperationException();
                if (!otherElement) otherElement = true;
                singleElement = element;
            }

            return singleElement;
        }


        public static TSource SingleOrDefault<TSource>(/*this*/ IEnumerable<TSource> source,
                Func<TSource, bool> predicate)
        {
            if (source == null || predicate == null)
                throw new ArgumentNullException();

            bool otherElement = false;
            TSource singleElement = default(TSource);
            foreach (TSource element in source)
            {
                if (predicate(element))
                {
                    if (otherElement) throw new InvalidOperationException();
                    if (!otherElement) otherElement = true;
                    singleElement = element;
                }
            }

            return singleElement;
        }

        #endregion

        #region Skip
        public static IEnumerable<TSource> Skip<TSource>(/*this*/ IEnumerable<TSource> source, int count)
        {
            if (source == null)
                throw new NotSupportedException();

            int i = 0;
            foreach (TSource e in source)
            {
                if (++i < count)
                    continue;
                yield return e;
            }
        }
        #endregion

        #region SkipWhile


        public static IEnumerable<T> SkipWhile<T>(
                IEnumerable<T> source,
                Func<T, bool> predicate)
        {
            if (source == null || predicate == null)
                throw new ArgumentNullException();

            bool yield = false;

            foreach (T element in source)
            {
                if (yield)
                    yield return element;
                else
                    if (!predicate(element))
                    {
                        yield return element;
                        yield = true;
                    }
            }
        }


        public static IEnumerable<TSource> SkipWhile<TSource>(/*this*/ IEnumerable<TSource> source,
                Func<TSource, int, bool> predicate)
        {
            if (source == null || predicate == null)
                throw new ArgumentNullException();

            int counter = 0;
            bool yield = false;

            foreach (TSource element in source)
            {
                if (yield)
                    yield return element;
                else
                    if (!predicate(element, counter))
                    {
                        yield return element;
                        yield = true;
                    }
                counter++;
            }
        }

        #endregion

        #region Sum

        public static int Sum(/*this*/ IEnumerable<int> source)
        {
            if (source == null)
                throw new ArgumentNullException("source");

            int sum = 0;
            foreach (int element in source)
                sum += element;

            return sum;
        }


        public static int Sum<TSource>(/*this*/ IEnumerable<TSource> source, Func<TSource, int> selector)
        {
            if (source == null || selector == null)
                throw new ArgumentNullException();

            int sum = 0;
            foreach (TSource element in source)
                sum += selector(element);

            return sum;
        }


        public static int? Sum(/*this*/ IEnumerable<int?> source)
        {
            if (source == null)
                throw new ArgumentNullException();

            int? sum = 0;
            foreach (int? element in source)
                if (element.HasValue)
                    sum += element.Value;

            return sum;
        }


        public static int? Sum<TSource>(/*this*/ IEnumerable<TSource> source, Func<TSource, int?> selector)
        {
            if (source == null || selector == null)
                throw new ArgumentNullException();

            int? sum = 0;
            foreach (TSource element in source)
            {
                int? item = selector(element);
                if (item.HasValue)
                    sum += item.Value;
            }

            return sum;
        }


        public static long Sum(/*this*/ IEnumerable<long> source)
        {
            if (source == null)
                throw new ArgumentNullException();

            long sum = 0;
            foreach (long element in source)
                sum += element;

            return sum;
        }


        public static long Sum<TSource>(/*this*/ IEnumerable<TSource> source, Func<TSource, long> selector)
        {
            if (source == null || selector == null)
                throw new ArgumentNullException();

            long sum = 0;
            foreach (TSource element in source)
                sum += selector(element);

            return sum;
        }


        public static long? Sum(/*this*/ IEnumerable<long?> source)
        {
            if (source == null)
                throw new ArgumentNullException();

            long? sum = 0;
            foreach (long? element in source)
                if (element.HasValue)
                    sum += element.Value;

            return sum;
        }


        public static long? Sum<TSource>(/*this*/ IEnumerable<TSource> source, Func<TSource, long?> selector)
        {
            if (source == null || selector == null)
                throw new ArgumentNullException();

            long? sum = 0;
            foreach (TSource element in source)
            {
                long? item = selector(element);
                if (item.HasValue)
                    sum += item.Value;
            }

            return sum;
        }


        public static double Sum(/*this*/ IEnumerable<double> source)
        {
            if (source == null)
                throw new ArgumentNullException();

            double sum = 0;
            foreach (double element in source)
                sum += element;

            return sum;
        }


        public static double Sum<TSource>(/*this*/ IEnumerable<TSource> source, Func<TSource, double> selector)
        {
            if (source == null || selector == null)
                throw new ArgumentNullException();

            double sum = 0;
            foreach (TSource element in source)
                sum += selector(element);

            return sum;
        }


        public static double? Sum(/*this*/ IEnumerable<double?> source)
        {
            if (source == null)
                throw new ArgumentNullException();

            double? sum = 0;
            foreach (double? element in source)
                if (element.HasValue)
                    sum += element.Value;

            return sum;
        }


        public static double? Sum<TSource>(/*this*/ IEnumerable<TSource> source, Func<TSource, double?> selector)
        {
            if (source == null || selector == null)
                throw new ArgumentNullException();

            double? sum = 0;
            foreach (TSource element in source)
            {
                double? item = selector(element);
                if (item.HasValue)
                    sum += item.Value;
            }

            return sum;
        }


        public static decimal Sum(/*this*/ IEnumerable<decimal> source)
        {
            if (source == null)
                throw new ArgumentNullException();

            decimal sum = 0;
            foreach (decimal element in source)
                sum += element;

            return sum;
        }


        public static decimal Sum<TSource>(/*this*/ IEnumerable<TSource> source, Func<TSource, decimal> selector)
        {
            if (source == null || selector == null)
                throw new ArgumentNullException();

            decimal sum = 0;
            foreach (TSource element in source)
                sum += selector(element);

            return sum;
        }


        public static decimal? Sum(/*this*/ IEnumerable<decimal?> source)
        {
            if (source == null)
                throw new ArgumentNullException();

            decimal? sum = 0;
            foreach (decimal? element in source)
                if (element.HasValue)
                    sum += element.Value;

            return sum;
        }


        public static decimal? Sum<TSource>(/*this*/ IEnumerable<TSource> source, Func<TSource, decimal?> selector)
        {
            if (source == null || selector == null)
                throw new ArgumentNullException();

            decimal? sum = 0;
            foreach (TSource element in source)
            {
                decimal? item = selector(element);
                if (item.HasValue)
                    sum += item.Value;
            }

            return sum;
        }

        #endregion
        #region Take

        public static IEnumerable<T> Take<T>(/*this*/ IEnumerable<T> source, int count)
        {
            if (source == null)
                throw new ArgumentNullException();

            if (count <= 0)
                yield break;
            else
            {
                int counter = 0;
                foreach (T element in source)
                {
                    yield return element;
                    counter++;
                    if (counter == count)
                        yield break;
                }
            }
        }

        #endregion

        #region TakeWhile

        public static IEnumerable<T> TakeWhile<T>(/*this*/ IEnumerable<T> source, Func<T, bool> predicate)
        {
            if (source == null || predicate == null)
                throw new ArgumentNullException();

            foreach (T element in source)
            {
                if (predicate(element))
                    yield return element;
                else
                    yield break;
            }
        }

        public static IEnumerable<TSource> TakeWhile<TSource>(/*this*/ IEnumerable<TSource> source, Func<TSource, int, bool> predicate)
        {
            if (source == null || predicate == null)
                throw new ArgumentNullException();

            int counter = 0;
            foreach (TSource element in source)
            {
                if (predicate(element, counter))
                    yield return element;
                else
                    yield break;
                counter++;
            }
        }

        #endregion

        #region ThenBy

        public static OrderedSequence<TSource> ThenBy<TSource, TKey>(/*this*/ OrderedSequence<TSource> source, Func<TSource, TKey> keySelector)
        {
            return ThenBy<TSource, TKey>(source, keySelector, null);
        }


        public static OrderedSequence<TSource> ThenBy<TSource, TKey>(/*this*/ OrderedSequence<TSource> source, 
            Func<TSource, TKey> keySelector, IComparer<TKey> comparer)
        {
            if (source == null || keySelector == null)
                throw new ArgumentNullException();

            return new InternalOrderedSequence<TSource, TKey>(
                    source, keySelector, (comparer ?? Comparer<TKey>.Default), false, source);
        }

        #endregion

        #region ThenByDescending

        public static OrderedSequence<TSource> ThenByDescending<TSource, TKey>(/*this*/ OrderedSequence<TSource> source,
            Func<TSource, TKey> keySelector)
        {
            return ThenByDescending<TSource, TKey>(source, keySelector, null);
        }


        public static OrderedSequence<TSource> ThenByDescending<TSource, TKey>(/*this*/ OrderedSequence<TSource> source,
            Func<TSource, TKey> keySelector, IComparer<TKey> comparer)
        {
            if (source == null || keySelector == null)
                throw new ArgumentNullException();

            return new InternalOrderedSequence<TSource, TKey>(
                    source, keySelector, (comparer ?? Comparer<TKey>.Default), true, source);
        }

        #endregion

        #region ToArray
        public static T[] ToArray<T> (/*this*/ IEnumerable<T> source)
        {
            if (source == null)
                throw new ArgumentNullException ();
                        
            List<T> list = new List<T> (source);
            return list.ToArray ();
        }
                
        #endregion

        #region ToDictionary
        public static Dictionary<TKey, TElement> ToDictionary<TSource, TKey, TElement>(/*this*/ IEnumerable<TSource> source, Func<TSource, TKey> keySelector, Func<TSource, TElement> elementSelector)
        {
            return ToDictionary<TSource, TKey, TElement>(source, keySelector, elementSelector, null);
        }


        public static Dictionary<TKey, TElement> ToDictionary<TSource, TKey, TElement>(/*this*/ IEnumerable<TSource> source, Func<TSource, TKey> keySelector, Func<TSource, TElement> elementSelector, IEqualityComparer<TKey> comparer)
        {
            if (source == null)
                throw new ArgumentNullException("source");
            if (keySelector == null)
                throw new ArgumentNullException("keySelector");
            if (elementSelector == null)
                throw new ArgumentNullException("elementSelector");

            Dictionary<TKey, TElement> dict = new Dictionary<TKey, TElement>(comparer);
            foreach (TSource e in source)
            {
                dict.Add(keySelector(e), elementSelector(e));
            }

            return dict;
        }
        #endregion

        #region ToList
        public static List<TSource> ToList<TSource>(/*this*/ IEnumerable<TSource> source)
        {
            if (source == null)
                throw new ArgumentNullException("source");

            return new List<TSource>(source);
        }
        #endregion

        #region ToLookup

        public static Lookup<TKey, TSource> ToLookup<TSource, TKey>(/*this*/ IEnumerable<TSource> source, Func<TSource, TKey> keySelector)
        {
            return ToLookup<TSource, TKey>(source, keySelector, null);
        }


        public static Lookup<TKey, TSource> ToLookup<TSource, TKey>(/*this*/ IEnumerable<TSource> source, 
            Func<TSource, TKey> keySelector, IEqualityComparer<TKey> comparer)
        {
            if (source == null || keySelector == null)
                throw new ArgumentNullException();

            Dictionary<TKey, List<TSource>> dictionary = new Dictionary<TKey, List<TSource>>(comparer ?? EqualityComparer<TKey>.Default);
            foreach (TSource element in source)
            {
                TKey key = keySelector(element);
                if (key == null)
                    throw new ArgumentNullException();
                if (!dictionary.ContainsKey(key))
                    dictionary.Add(key, new List<TSource>());
                dictionary[key].Add(element);
            }
            return new Lookup<TKey, TSource>(dictionary);
        }


        public static Lookup<TKey, TElement> ToLookup<TSource, TKey, TElement>(/*this*/ IEnumerable<TSource> source,
            Func<TSource, TKey> keySelector, Func<TSource, TElement> elementSelector)
        {
            return ToLookup<TSource, TKey, TElement>(source, keySelector, elementSelector, null);
        }


        public static Lookup<TKey, TElement> ToLookup<TSource, TKey, TElement>(/*this*/ IEnumerable<TSource> source,
            Func<TSource, TKey> keySelector, Func<TSource, TElement> elementSelector, IEqualityComparer<TKey> comparer)
        {
            if (source == null || keySelector == null || elementSelector == null)
                throw new ArgumentNullException();

            Dictionary<TKey, List<TElement>> dictionary = new Dictionary<TKey, List<TElement>>(comparer ?? EqualityComparer<TKey>.Default);
            foreach (TSource element in source)
            {
                TKey key = keySelector(element);
                if (key == null)
                    throw new ArgumentNullException();
                if (!dictionary.ContainsKey(key))
                    dictionary.Add(key, new List<TElement>());
                dictionary[key].Add(elementSelector(element));
            }
            return new Lookup<TKey, TElement>(dictionary);
        }

        #endregion

        #region ToSequence

        public static IEnumerable<T> ToSequence<T>(/*this*/ IEnumerable<T> source)
        {
            return (IEnumerable<T>)source;
        }

        #endregion

        #region Union


        public static IEnumerable<T> Union<T>(/*this*/ IEnumerable<T> first, IEnumerable<T> second)
        {
            if (first == null || second == null)
                throw new ArgumentNullException();

            List<T> items = new List<T>();
            foreach (T element in first)
            {
                if (IndexOf(items, element) == -1)
                {
                    items.Add(element);
                    yield return element;
                }
            }
            foreach (T element in second)
            {
                if (IndexOf(items, element) == -1)
                {
                    items.Add(element);
                    yield return element;
                }
            }
        }

        #endregion

        #region Where

        public static IEnumerable<TSource> Where<TSource>(/*this*/ IEnumerable<TSource> source,
                Func<TSource, bool> predicate)
        {
            if (source == null || predicate == null)
                throw new ArgumentNullException();

            foreach (TSource element in source)
                if (predicate(element))
                    yield return element;
        }


        public static IEnumerable<TSource> Where<TSource>(/*this*/ IEnumerable<TSource> source,
                Func<TSource, int, bool> predicate)
        {
            if (source == null || predicate == null)
                throw new ArgumentNullException();

            int counter = 0;
            foreach (TSource element in source)
            {
                if (predicate(element, counter))
                    yield return element;
                counter++;
            }
        }

        #endregion

        // These methods are not included in the
        // .NET Standard Query Operators Specification,
        // but they provide additional useful commands

        #region Compare

        private static bool Equals<T>(T first, T second)
        {
            // Mostly, values in Enumerable<T> 
            // sequences need to be compared using
            // Equals and GetHashCode

            if (first == null || second == null)
                return (first == null && second == null);
            else
                return ((first.Equals(second) ||
                         first.GetHashCode() == second.GetHashCode()));
        }

        #endregion

        #region IndexOf

        public static int IndexOf<T>(/*this*/ IEnumerable<T> source, T item, IEqualityComparer<T> comparer)
        {
            if (comparer == null)
                comparer = EqualityComparer<T>.Default;

            int counter = 0;
            foreach (T element in source)
            {
                if (comparer.Equals(element, item))
                    return counter;
                counter++;
            }
            // The item was not found
            return -1;
        }

        public static int IndexOf<T>(/*this*/ IEnumerable<T> source, T item)
        {
            return IndexOf<T>(source, item, null);
        }
        #endregion

        #region ToReadOnlyCollection
        internal static ReadOnlyCollection<TSource> ToReadOnlyCollection<TSource>(IEnumerable<TSource> source)
        {
            if (source == null)
                return new ReadOnlyCollection<TSource>(new List<TSource>());

            if (typeof(ReadOnlyCollection<TSource>).IsInstanceOfType(source))
                return source as ReadOnlyCollection<TSource>;

            return new ReadOnlyCollection<TSource>(ToArray<TSource>(source));
        }
        #endregion
    }
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The MIT License


Written By
Software Developer None
Canada Canada
Since I started programming when I was 11, I wrote the SNES emulator "SNEqr", the FastNav mapping component, the Enhanced C# programming language (in progress), the parser generator LLLPG, and LES, a syntax to help you start building programming languages, DSLs or build systems.

My overall focus is on the Language of your choice (Loyc) initiative, which is about investigating ways to improve interoperability between programming languages and putting more power in the hands of developers. I'm also seeking employment.

Comments and Discussions