#if NET20 || NET30 || !NET_4_6 using System.Collections; using System.Collections.Generic; using LinqInternal.Collections.Specialized; using LinqInternal.Core; namespace System.Linq.Reimplement { public static partial class Enumerable { public static IEnumerable> GroupBy(this IEnumerable source, Func keySelector) { return GroupBy(source, keySelector, null); } public static IEnumerable> GroupBy(this IEnumerable source, Func keySelector, IEqualityComparer comparer) { return new GroupedEnumerable(source, keySelector, FuncHelper.GetIdentityFunc(), comparer); } public static IEnumerable> GroupBy(this IEnumerable source, Func keySelector, Func elementSelector) { return GroupBy(source, keySelector, elementSelector, null); } public static IEnumerable> GroupBy(this IEnumerable source, Func keySelector, Func elementSelector, IEqualityComparer comparer) { LinqCheck.SourceAndKeyElementSelectors(source, keySelector, elementSelector); return CreateGroupByIterator(source, keySelector, elementSelector, comparer); } public static IEnumerable GroupBy(this IEnumerable source, Func keySelector, Func elementSelector, Func, TResult> resultSelector) { return GroupBy(source, keySelector, elementSelector, resultSelector, null); } public static IEnumerable GroupBy(this IEnumerable source, Func keySelector, Func elementSelector, Func, TResult> resultSelector, IEqualityComparer comparer) { LinqCheck.GroupBySelectors(source, keySelector, elementSelector, resultSelector); return CreateGroupByIterator(source, keySelector, elementSelector, resultSelector, comparer); } public static IEnumerable GroupBy(this IEnumerable source, Func keySelector, Func, TResult> resultSelector) { return GroupBy(source, keySelector, resultSelector, null); } public static IEnumerable GroupBy(this IEnumerable source, Func keySelector, Func, TResult> resultSelector, IEqualityComparer comparer) { return new GroupedEnumerable(source, keySelector, FuncHelper.GetIdentityFunc(), resultSelector, comparer); } private static IEnumerable> CreateGroupByIterator(this IEnumerable source, Func keySelector, Func elementSelector, IEqualityComparer comparer) { return new GroupedEnumerable(source, keySelector, elementSelector, comparer)/* as IEnumerable>*/; } private static IEnumerable CreateGroupByIterator(this IEnumerable source, Func keySelector, Func elementSelector, Func, TResult> resultSelector, IEqualityComparer comparer) { return new GroupedEnumerable(source, keySelector, elementSelector, resultSelector, comparer)/* as IEnumerable*/; } internal class GroupedEnumerable : IEnumerable { private readonly IEqualityComparer _comparer; private readonly Func _elementSelector; private readonly Func _keySelector; private readonly Func, TResult> _resultSelector; private readonly IEnumerable _source; public GroupedEnumerable(IEnumerable source, Func keySelector, Func elementSelector, Func, TResult> resultSelector, IEqualityComparer comparer) { if (source == null) { throw new ArgumentNullException("source"); } if (keySelector == null) { throw new ArgumentNullException("keySelector"); } if (elementSelector == null) { throw new ArgumentNullException("elementSelector"); } if (resultSelector == null) { throw new ArgumentNullException("resultSelector"); } _source = source; _keySelector = keySelector; _elementSelector = elementSelector; _resultSelector = resultSelector; _comparer = comparer; } public IEnumerator GetEnumerator() { var groupings = new NullAwareDictionary.Grouping>(_comparer); foreach (var item in _source) { var key = _keySelector(item); Lookup.Grouping grouping; if (!groupings.TryGetValue(key, out grouping)) { grouping = new Lookup.Grouping(key); groupings.Add(key, grouping); } grouping.Items.Add(_elementSelector(item)); } return Enumerator(groupings); } IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } private IEnumerator Enumerator(IDictionary.Grouping> groupings) { foreach (var grouping in groupings.Values) { yield return _resultSelector(grouping.Key, grouping.Items); } } } internal class GroupedEnumerable : IEnumerable> { private readonly IEqualityComparer _comparer; private readonly Func _elementSelector; private readonly Func _keySelector; private readonly IEnumerable _source; public GroupedEnumerable(IEnumerable source, Func keySelector, Func elementSelector, IEqualityComparer comparer) { if (source == null) { throw new ArgumentNullException("source"); } if (keySelector == null) { throw new ArgumentNullException("keySelector"); } if (elementSelector == null) { throw new ArgumentNullException("elementSelector"); } _source = source; _keySelector = keySelector; _elementSelector = elementSelector; _comparer = comparer; } public IEnumerator> GetEnumerator() { var groupings = new NullAwareDictionary.Grouping>(_comparer); foreach (var item in _source) { var key = _keySelector(item); Lookup.Grouping grouping; if (!groupings.TryGetValue(key, out grouping)) { grouping = new Lookup.Grouping(key); groupings.Add(key, grouping); } grouping.Items.Add(_elementSelector(item)); } return Enumerator(groupings); } IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } private static IEnumerator> Enumerator(IDictionary.Grouping> groupings) { foreach (var grouping in groupings.Values) { yield return grouping; } } } } } #endif