diff --git a/ShittyLINQ/GroupBy.cs b/ShittyLINQ/GroupBy.cs new file mode 100644 index 0000000..0ab4165 --- /dev/null +++ b/ShittyLINQ/GroupBy.cs @@ -0,0 +1,180 @@ +using System; +using System.Collections.Generic; + +namespace ShittyLINQ +{ + public static partial class Extensions + { + /// + /// Groups the elements of a sequence. + /// + /// An IEnumerable whose elements to group. + /// A function to extract the key for each element. + /// Source type + /// Key type + /// A collection of elements where each element represents a projection over a group and its key. + /// If source, keySelector or element Selector is null + public static Dictionary> GroupBy( + this IEnumerable source, + Func keySelector) + { + return GroupBy(source, keySelector, t => t, EqualityComparer.Default); + } + + + /// + /// Groups the elements of a sequence. + /// + /// An IEnumerable whose elements to group. + /// A function to extract the key for each element. + /// An IEqualityComparer to compare keys with. + /// Source type + /// Key type + /// A collection of elements where each element represents a projection over a group and its key. + /// If source, keySelector or element Selector is null + public static Dictionary> GroupBy( + this IEnumerable source, + Func keySelector, + IEqualityComparer comparer) + { + return GroupBy(source, keySelector, t => t, comparer); + } + + + /// + /// Groups the elements of a sequence. + /// + /// An IEnumerable whose elements to group. + /// A function to extract the key for each element. + /// A function to map each source element to an element in an IGrouping + /// Source type + /// Key type + /// Value type + /// A collection of elements where each element represents a projection over a group and its key. + /// If source, keySelector or element Selector is null + public static Dictionary> GroupBy( + this IEnumerable source, + Func keySelector, + Func elementSelector) + { + return GroupBy(source, keySelector, elementSelector, EqualityComparer.Default); + } + + + /// + /// Groups the elements of a sequence. + /// + /// An IEnumerable whose elements to group. + /// A function to extract the key for each element. + /// A function to map each source element to an element in an IGrouping + /// Source type + /// Key type + /// Value type + /// An IEqualityComparer to compare keys with. + /// A collection of elements where each element represents a projection over a group and its key. + /// If source, keySelector or element Selector is null + public static Dictionary> GroupBy( + this IEnumerable source, + Func keySelector, + Func elementSelector, + IEqualityComparer comparer) + { + if (source == null || keySelector == null || elementSelector == null) + throw new ArgumentNullException(); + + Dictionary> res = new Dictionary>(comparer ?? EqualityComparer.Default); + + foreach (TSource item in source) + { + var subset = source.Where(b => keySelector(b).Equals(keySelector(item))).Select(a => elementSelector(a)).ToList(); + if (!res.ContainsKey(keySelector(item))) + { + res.Add(keySelector(item), subset); + } + } + return res; + } + + /// + /// Groups the elements of a sequence. + /// + /// An IEnumerable whose elements to group. + /// A function to extract the key for each element. + /// A function to create a result value from each group. + /// An IEqualityComparer to compare keys with. + /// Source type + /// Key type + /// The type of the result value returned by resultSelector + /// A collection of elements of type TResult where each element represents a projection over a group and its key. + /// If source, keySelector or element Selector is null + public static IEnumerable GroupBy( + this IEnumerable source, + Func keySelector, + Func, TResult> resultSelector) + { + return GroupBy(source, keySelector, t => t, resultSelector, EqualityComparer.Default); + } + + + /// + /// Groups the elements of a sequence. + /// + /// An IEnumerable whose elements to group. + /// A function to extract the key for each element. + /// A function to create a result value from each group. + /// An IEqualityComparer to compare keys with. + /// Source type + /// Key type + /// The type of the result value returned by resultSelector + /// A collection of elements of type TResult where each element represents a projection over a group and its key. + /// If source, keySelector or element Selector is null + public static IEnumerable GroupBy( + this IEnumerable source, + Func keySelector, + Func, TResult> resultSelector, + IEqualityComparer comparer) + { + return GroupBy(source, keySelector, t => t, resultSelector, comparer); + } + + + + + /// + /// Groups the elements of a sequence. + /// + /// An IEnumerable whose elements to group. + /// A function to extract the key for each element. + /// A function to map each source element to an element in an IGrouping + /// A function to create a result value from each group. + /// An IEqualityComparer to compare keys with. + /// Source type + /// Key type + /// Value type + /// The type of the result value returned by resultSelector + /// A collection of elements of type TResult where each element represents a projection over a group and its key. + /// If source, keySelector or element Selector is null + public static IEnumerable GroupBy( + IEnumerable source, + Func keySelector, + Func elementSelector, + Func, TResult> resultSelector, + IEqualityComparer comparer) + { + if (source == null || keySelector == null || elementSelector == null || resultSelector == null || comparer == null) + throw new ArgumentNullException(); + + List res = new List(); + + foreach (TSource item in source) + { + var subset = source.Where(b => keySelector(b).Equals(keySelector(item))).Select(a => elementSelector(a)).ToList(); + if (!res.Contains(resultSelector(keySelector(item), subset))) + { + res.Add(resultSelector(keySelector(item), subset)); + } + } + return res; + } + } +} diff --git a/ShittyLinqTests/GroupByTests.cs b/ShittyLinqTests/GroupByTests.cs new file mode 100644 index 0000000..2eef660 --- /dev/null +++ b/ShittyLinqTests/GroupByTests.cs @@ -0,0 +1,47 @@ +using System.Collections.Generic; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using ShittyLINQ; +using ShittyTests.TestHelpers; + +namespace ShittyTests +{ + [TestClass] + public class GroupByTests + { + + [TestMethod] + public void GroupBy_Person() + { + var adam = new Person("Adam", 20, "Arquitech", "Amber"); + var brian = new Person("Brian", 45, "Arquitech", "Blue"); + var charles = new Person("Charles", 33, "Arquitech", "Cyan"); + var dani = new Person("Dani", 33, "Developer", "Deep Purple"); + IEnumerable people = new[] { adam, brian, charles, dani }; + + var result = people.GroupBy(person => person.Age); + + Assert.AreEqual(result.Count, 3); + Assert.AreEqual(result.GetValueOrDefault(20).First(), adam); + } + + [TestMethod] + public void GroupBy_Person_WithResultSelector() + { + var adam = new Person("Adam", 20, "Arquitech", "Amber"); + var brian = new Person("Brian", 45, "Arquitech", "Blue"); + var charles = new Person("Charles", 33, "Arquitech", "Cyan"); + var dani = new Person("Dani", 33, "Developer", "Deep Purple"); + IEnumerable people = new[] { adam, brian, charles, dani }; + + var result = people.GroupBy(person => person.Age, + (baseAge, ages) => new + { + Key = baseAge, + Count = (int)ages.Count() + }); + + Assert.AreEqual(result.ToList().Count, 3); + Assert.AreEqual(result.ToList().Max(a => a.Count), 2); + } + } +} \ No newline at end of file