Skip to content

Commit bab461e

Browse files
committed
GroupBy method and tests
1 parent 36a4b88 commit bab461e

File tree

2 files changed

+227
-0
lines changed

2 files changed

+227
-0
lines changed

ShittyLINQ/GroupBy.cs

Lines changed: 180 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,180 @@
1+
using System;
2+
using System.Collections.Generic;
3+
4+
namespace ShittyLINQ
5+
{
6+
public static partial class Extensions
7+
{
8+
/// <summary>
9+
/// Groups the elements of a sequence.
10+
/// </summary>
11+
/// <param name="source">An IEnumerable<T> whose elements to group.</param>
12+
/// <param name="keySelector">A function to extract the key for each element.</param>
13+
/// <typeparam name="TSource">Source type</typeparam>
14+
/// <typeparam name="TKey">Key type</typeparam>
15+
/// <returns> A collection of elements where each element represents a projection over a group and its key.</returns>
16+
/// <exception cref="ArgumentNullException">If source, keySelector or element Selector is null</exception>
17+
public static Dictionary<TKey, IEnumerable<TSource>> GroupBy<TSource, TKey>(
18+
this IEnumerable<TSource> source,
19+
Func<TSource, TKey> keySelector)
20+
{
21+
return GroupBy(source, keySelector, t => t, EqualityComparer<TKey>.Default);
22+
}
23+
24+
25+
/// <summary>
26+
/// Groups the elements of a sequence.
27+
/// </summary>
28+
/// <param name="source">An IEnumerable<T> whose elements to group.</param>
29+
/// <param name="keySelector">A function to extract the key for each element.</param>
30+
/// <param name="comparer">An IEqualityComparer<T> to compare keys with.</param>
31+
/// <typeparam name="TSource">Source type</typeparam>
32+
/// <typeparam name="TKey">Key type</typeparam>
33+
/// <returns> A collection of elements where each element represents a projection over a group and its key.</returns>
34+
/// <exception cref="ArgumentNullException">If source, keySelector or element Selector is null</exception>
35+
public static Dictionary<TKey, IEnumerable<TSource>> GroupBy<TSource, TKey>(
36+
this IEnumerable<TSource> source,
37+
Func<TSource, TKey> keySelector,
38+
IEqualityComparer<TKey> comparer)
39+
{
40+
return GroupBy(source, keySelector, t => t, comparer);
41+
}
42+
43+
44+
/// <summary>
45+
/// Groups the elements of a sequence.
46+
/// </summary>
47+
/// <param name="source">An IEnumerable<T> whose elements to group.</param>
48+
/// <param name="keySelector">A function to extract the key for each element.</param>
49+
/// <param name="elementSelector">A function to map each source element to an element in an IGrouping<TKey,TElement></param>
50+
/// <typeparam name="TSource">Source type</typeparam>
51+
/// <typeparam name="TKey">Key type</typeparam>
52+
/// <typeparam name="TElement">Value type</typeparam>
53+
/// <returns> A collection of elements where each element represents a projection over a group and its key.</returns>
54+
/// <exception cref="ArgumentNullException">If source, keySelector or element Selector is null</exception>
55+
public static Dictionary<TKey, IEnumerable<TElement>> GroupBy<TSource, TKey, TElement>(
56+
this IEnumerable<TSource> source,
57+
Func<TSource, TKey> keySelector,
58+
Func<TSource, TElement> elementSelector)
59+
{
60+
return GroupBy(source, keySelector, elementSelector, EqualityComparer<TKey>.Default);
61+
}
62+
63+
64+
/// <summary>
65+
/// Groups the elements of a sequence.
66+
/// </summary>
67+
/// <param name="source">An IEnumerable<T> whose elements to group.</param>
68+
/// <param name="keySelector">A function to extract the key for each element.</param>
69+
/// <param name="elementSelector">A function to map each source element to an element in an IGrouping<TKey,TElement></param>
70+
/// <typeparam name="TSource">Source type</typeparam>
71+
/// <typeparam name="TKey">Key type</typeparam>
72+
/// <typeparam name="TElement">Value type</typeparam>
73+
/// <param name="comparer">An IEqualityComparer<T> to compare keys with.</param>
74+
/// <returns> A collection of elements where each element represents a projection over a group and its key.</returns>
75+
/// <exception cref="ArgumentNullException">If source, keySelector or element Selector is null</exception>
76+
public static Dictionary<TKey, IEnumerable<TElement>> GroupBy<TSource, TKey, TElement>(
77+
this IEnumerable<TSource> source,
78+
Func<TSource, TKey> keySelector,
79+
Func<TSource, TElement> elementSelector,
80+
IEqualityComparer<TKey> comparer)
81+
{
82+
if (source == null || keySelector == null || elementSelector == null)
83+
throw new ArgumentNullException();
84+
85+
Dictionary<TKey, IEnumerable<TElement>> res = new Dictionary<TKey, IEnumerable<TElement>>(comparer ?? EqualityComparer<TKey>.Default);
86+
87+
foreach (TSource item in source)
88+
{
89+
var subset = source.Where(b => keySelector(b).Equals(keySelector(item))).Select(a => elementSelector(a)).ToList();
90+
if (!res.ContainsKey(keySelector(item)))
91+
{
92+
res.Add(keySelector(item), subset);
93+
}
94+
}
95+
return res;
96+
}
97+
98+
/// <summary>
99+
/// Groups the elements of a sequence.
100+
/// </summary>
101+
/// <param name="source">An IEnumerable<T> whose elements to group.</param>
102+
/// <param name="keySelector">A function to extract the key for each element.</param>
103+
/// <param name="resultSelector">A function to create a result value from each group.</param>
104+
/// <param name="comparer">An IEqualityComparer<T> to compare keys with.</param>
105+
/// <typeparam name="TSource">Source type</typeparam>
106+
/// <typeparam name="TKey">Key type</typeparam>
107+
/// <typeparam name="TResult">The type of the result value returned by resultSelector</typeparam>
108+
/// <returns> A collection of elements of type TResult where each element represents a projection over a group and its key.</returns>
109+
/// <exception cref="ArgumentNullException">If source, keySelector or element Selector is null</exception>
110+
public static IEnumerable<TResult> GroupBy<TSource, TKey, TResult>(
111+
this IEnumerable<TSource> source,
112+
Func<TSource, TKey> keySelector,
113+
Func<TKey, IEnumerable<TSource>, TResult> resultSelector)
114+
{
115+
return GroupBy(source, keySelector, t => t, resultSelector, EqualityComparer<TKey>.Default);
116+
}
117+
118+
119+
/// <summary>
120+
/// Groups the elements of a sequence.
121+
/// </summary>
122+
/// <param name="source">An IEnumerable<T> whose elements to group.</param>
123+
/// <param name="keySelector">A function to extract the key for each element.</param>
124+
/// <param name="resultSelector">A function to create a result value from each group.</param>
125+
/// <param name="comparer">An IEqualityComparer<T> to compare keys with.</param>
126+
/// <typeparam name="TSource">Source type</typeparam>
127+
/// <typeparam name="TKey">Key type</typeparam>
128+
/// <typeparam name="TResult">The type of the result value returned by resultSelector</typeparam>
129+
/// <returns> A collection of elements of type TResult where each element represents a projection over a group and its key.</returns>
130+
/// <exception cref="ArgumentNullException">If source, keySelector or element Selector is null</exception>
131+
public static IEnumerable<TResult> GroupBy<TSource, TKey, TResult>(
132+
this IEnumerable<TSource> source,
133+
Func<TSource, TKey> keySelector,
134+
Func<TKey, IEnumerable<TSource>, TResult> resultSelector,
135+
IEqualityComparer<TKey> comparer)
136+
{
137+
return GroupBy(source, keySelector, t => t, resultSelector, comparer);
138+
}
139+
140+
141+
142+
143+
/// <summary>
144+
/// Groups the elements of a sequence.
145+
/// </summary>
146+
/// <param name="source">An IEnumerable<T> whose elements to group.</param>
147+
/// <param name="keySelector">A function to extract the key for each element.</param>
148+
/// <param name="elementSelector">A function to map each source element to an element in an IGrouping<TKey,TElement></param>
149+
/// <param name="resultSelector">A function to create a result value from each group.</param>
150+
/// <param name="comparer">An IEqualityComparer<T> to compare keys with.</param>
151+
/// <typeparam name="TSource">Source type</typeparam>
152+
/// <typeparam name="TKey">Key type</typeparam>
153+
/// <typeparam name="TElement">Value type</typeparam>
154+
/// <typeparam name="TResult">The type of the result value returned by resultSelector</typeparam>
155+
/// <returns> A collection of elements of type TResult where each element represents a projection over a group and its key.</returns>
156+
/// <exception cref="ArgumentNullException">If source, keySelector or element Selector is null</exception>
157+
public static IEnumerable<TResult> GroupBy<TSource, TKey, TElement, TResult>(
158+
IEnumerable<TSource> source,
159+
Func<TSource, TKey> keySelector,
160+
Func<TSource, TElement> elementSelector,
161+
Func<TKey, IEnumerable<TElement>, TResult> resultSelector,
162+
IEqualityComparer<TKey> comparer)
163+
{
164+
if (source == null || keySelector == null || elementSelector == null || resultSelector == null || comparer == null)
165+
throw new ArgumentNullException();
166+
167+
List<TResult> res = new List<TResult>();
168+
169+
foreach (TSource item in source)
170+
{
171+
var subset = source.Where(b => keySelector(b).Equals(keySelector(item))).Select(a => elementSelector(a)).ToList();
172+
if (!res.Contains(resultSelector(keySelector(item), subset)))
173+
{
174+
res.Add(resultSelector(keySelector(item), subset));
175+
}
176+
}
177+
return res;
178+
}
179+
}
180+
}

ShittyLinqTests/GroupByTests.cs

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
using System.Collections.Generic;
2+
using Microsoft.VisualStudio.TestTools.UnitTesting;
3+
using ShittyLINQ;
4+
using ShittyTests.TestHelpers;
5+
6+
namespace ShittyTests
7+
{
8+
[TestClass]
9+
public class GroupByTests
10+
{
11+
12+
[TestMethod]
13+
public void GroupBy_Person()
14+
{
15+
var adam = new Person("Adam", 20, "Arquitech", "Amber");
16+
var brian = new Person("Brian", 45, "Arquitech", "Blue");
17+
var charles = new Person("Charles", 33, "Arquitech", "Cyan");
18+
var dani = new Person("Dani", 33, "Developer", "Deep Purple");
19+
IEnumerable<Person> people = new[] { adam, brian, charles, dani };
20+
21+
var result = people.GroupBy(person => person.Age);
22+
23+
Assert.AreEqual(result.Count, 3);
24+
Assert.AreEqual(result.GetValueOrDefault(20).First(), adam);
25+
}
26+
27+
[TestMethod]
28+
public void GroupBy_Person_WithResultSelector()
29+
{
30+
var adam = new Person("Adam", 20, "Arquitech", "Amber");
31+
var brian = new Person("Brian", 45, "Arquitech", "Blue");
32+
var charles = new Person("Charles", 33, "Arquitech", "Cyan");
33+
var dani = new Person("Dani", 33, "Developer", "Deep Purple");
34+
IEnumerable<Person> people = new[] { adam, brian, charles, dani };
35+
36+
var result = people.GroupBy(person => person.Age,
37+
(baseAge, ages) => new
38+
{
39+
Key = baseAge,
40+
Count = (int)ages.Count()
41+
});
42+
43+
Assert.AreEqual(result.ToList().Count, 3);
44+
Assert.AreEqual(result.ToList().Max(a => a.Count), 2);
45+
}
46+
}
47+
}

0 commit comments

Comments
 (0)