Skip to content

Commit c0a382c

Browse files
committed
+ GroupBy, some fixes
1 parent 85615e1 commit c0a382c

File tree

11 files changed

+646
-4
lines changed

11 files changed

+646
-4
lines changed

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@ finally
6666
- `Filter` - prevent items from passing through which don't pass a predicate
6767
- `First` - signals the first item of the async sequence
6868
- `FlatMap` - map the source items into `IAsyncEnumerable`s and merge their values into a single async sequence
69+
- `GroupBy` - groups the source elements into distinct async groups
6970
- `IgnoreElements` - ignores items and ends when the source async sequence ends
7071
- `Last` - signals the last item of the async sequence
7172
- `Map` - transform one source value into some other value
@@ -85,6 +86,7 @@ finally
8586
- `TakeUntil` - take items from the main source until a secondary async sequence signals an item or completes
8687
- `TakeWhile` - take items while predicate is true and stop when it turns false
8788
- `Timeout` - signal an error if the next item doesn't arrive within the specified time
89+
- `ToList` - collects all items into a List and signals it as the single result of the async sequence
8890

8991
## End-consumers
9092

Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
using System;
2+
using Xunit;
3+
using async_enumerable_dotnet;
4+
using System.Threading.Tasks;
5+
using System.Collections.Generic;
6+
using System.Linq;
7+
8+
namespace async_enumerable_dotnet_test
9+
{
10+
public class GroupByTest
11+
{
12+
[Fact]
13+
public async void Normal_Same_Group()
14+
{
15+
await AsyncEnumerable.Range(1, 10)
16+
.GroupBy(k => 1)
17+
.FlatMap(v => v.ToList())
18+
.AssertResult(
19+
ListOf(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
20+
);
21+
}
22+
23+
[Fact]
24+
public async void Normal_Distinct_Group()
25+
{
26+
await AsyncEnumerable.Range(1, 10)
27+
.GroupBy(k => k)
28+
.FlatMap(v => v.ToList())
29+
.AssertResultSet(
30+
ListComparer<int>.Default,
31+
ListOf(1),
32+
ListOf(2),
33+
ListOf(3),
34+
ListOf(4),
35+
ListOf(5),
36+
ListOf(6),
37+
ListOf(7),
38+
ListOf(8),
39+
ListOf(9),
40+
ListOf(10)
41+
);
42+
}
43+
44+
[Fact]
45+
public async void Normal_Mixed()
46+
{
47+
var disposed = 0;
48+
49+
await AsyncEnumerable.Range(1, 10)
50+
.DoOnDispose(() => disposed++)
51+
.GroupBy(k => k % 2)
52+
.FlatMap(v => v.ToList())
53+
.AssertResultSet(
54+
ListComparer<int>.Default,
55+
ListOf(1, 3, 5, 7, 9),
56+
ListOf(2, 4, 6, 8, 10)
57+
);
58+
59+
Assert.Equal(1, disposed);
60+
}
61+
62+
[Fact]
63+
public async void Normal_Ordered()
64+
{
65+
await AsyncEnumerable.Range(1, 10)
66+
.GroupBy(k => k < 6)
67+
.FlatMap(v => v.ToList())
68+
.AssertResultSet(
69+
ListComparer<int>.Default,
70+
ListOf(1, 2, 3, 4, 5),
71+
ListOf(6, 7, 8, 9, 10)
72+
);
73+
}
74+
75+
[Fact]
76+
public async void Take_2_Groups()
77+
{
78+
await AsyncEnumerable.Range(1, 10)
79+
.GroupBy(k => k % 3)
80+
.Take(2)
81+
.FlatMap(v => v.ToList())
82+
.AssertResultSet(
83+
ListComparer<int>.Default,
84+
ListOf(1, 4, 7, 10),
85+
ListOf(2, 5, 8)
86+
);
87+
}
88+
89+
[Fact]
90+
public async void Take_1_Of_Each_Group()
91+
{
92+
await AsyncEnumerable.Range(1, 10)
93+
.GroupBy(k => k)
94+
.FlatMap(v => v.Take(1))
95+
.AssertResultSet(
96+
1, 2, 3, 4, 5, 6, 7, 8, 9, 10
97+
);
98+
}
99+
100+
[Fact]
101+
public async void Take_1_Of_Each_Group_Two_Groups_Total()
102+
{
103+
var disposed = 0;
104+
105+
await AsyncEnumerable.Range(1, 10)
106+
.DoOnDispose(() => disposed++)
107+
.GroupBy(k => k)
108+
.Take(2)
109+
.FlatMap(v => v.Take(1))
110+
.AssertResultSet(
111+
1, 2
112+
);
113+
114+
Assert.Equal(1, disposed);
115+
}
116+
117+
static List<int> ListOf(params int[] values)
118+
{
119+
return new List<int>(values);
120+
}
121+
}
122+
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Linq;
4+
using System.Text;
5+
6+
namespace async_enumerable_dotnet_test
7+
{
8+
internal sealed class ListComparer<T> : IEqualityComparer<IList<T>>
9+
{
10+
internal static readonly ListComparer<T> Default = new ListComparer<T>();
11+
12+
public bool Equals(IList<T> x, IList<T> y)
13+
{
14+
return x.SequenceEqual(y);
15+
}
16+
17+
public int GetHashCode(IList<T> obj)
18+
{
19+
var hash = 19;
20+
21+
unchecked
22+
{
23+
foreach (var t in obj)
24+
{
25+
hash = hash * 31 + (t != null ? t.GetHashCode() : 0);
26+
}
27+
}
28+
29+
return hash;
30+
}
31+
}
32+
}

async-enumerable-dotnet-test/TestHelper.cs

Lines changed: 32 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
using async_enumerable_dotnet;
22
using System;
3+
using System.Collections;
34
using System.Collections.Generic;
45
using System.Reflection;
56
using System.Text;
@@ -35,15 +36,22 @@ public static async ValueTask AssertResult<T>(this IAsyncEnumerator<T> source, p
3536
}
3637
}
3738

38-
public static async ValueTask AssertResultSet<T>(this IAsyncEnumerable<T> source, params T[] values)
39+
public static ValueTask AssertResultSet<T>(this IAsyncEnumerable<T> source, params T[] values)
3940
{
40-
var set = new HashSet<T>(values);
41+
return AssertResultSet(source, EqualityComparer<T>.Default, values);
42+
}
43+
44+
public static async ValueTask AssertResultSet<T>(this IAsyncEnumerable<T> source, IEqualityComparer<T> comparer, params T[] values)
45+
{
46+
var set = new HashSet<T>(values, comparer);
4147
var en = source.GetAsyncEnumerator();
4248
try
4349
{
4450
while (await en.MoveNextAsync())
4551
{
46-
Assert.True(set.Remove(en.Current));
52+
var c = en.Current;
53+
Assert.Contains(c, set);
54+
Assert.True(set.Remove(c), "Unexpected item: " + AsString(c));
4755
}
4856

4957
Assert.Empty(set);
@@ -54,6 +62,27 @@ public static async ValueTask AssertResultSet<T>(this IAsyncEnumerable<T> source
5462
}
5563
}
5664

65+
static string AsString(object obj)
66+
{
67+
if (obj is IEnumerable en)
68+
{
69+
var sb = new StringBuilder("[");
70+
var i = 0;
71+
foreach (var o in en)
72+
{
73+
if (i != 0)
74+
{
75+
sb.Append(", ");
76+
}
77+
sb.Append(o);
78+
i++;
79+
}
80+
sb.Append("]");
81+
return sb.ToString();
82+
}
83+
return obj != null ? obj.ToString() : "null";
84+
}
85+
5786
public static ValueTask AssertFailure<T>(this IAsyncEnumerable<T> source, Type exception, params T[] values)
5887
{
5988
return AssertFailure(source.GetAsyncEnumerator(), exception, values);
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
using System;
2+
using Xunit;
3+
using async_enumerable_dotnet;
4+
using System.Threading.Tasks;
5+
using System.Collections.Generic;
6+
using static async_enumerable_dotnet_test.GroupByTest;
7+
8+
namespace async_enumerable_dotnet_test
9+
{
10+
public class TestHelperTest
11+
{
12+
[Fact]
13+
public async void AssertResultSet()
14+
{
15+
await AsyncEnumerable.Range(1, 3)
16+
.AssertResultSet(1, 2, 3);
17+
}
18+
19+
[Fact]
20+
public async void AssertResultSet_List()
21+
{
22+
await AsyncEnumerable.FromArray(new List<int>(new [] { 1, 2, 3 }))
23+
.AssertResultSet(
24+
ListComparer<int>.Default,
25+
new List<int>(new[] { 1, 2, 3 }));
26+
}
27+
28+
[Fact]
29+
public void HashSet_Contains()
30+
{
31+
var set = new HashSet<IList<int>>(ListComparer<int>.Default);
32+
33+
set.Add(new List<int>(new[] { 1, 2, 3 }));
34+
35+
Assert.Contains(new List<int>(new[] { 1, 2, 3 }), set);
36+
37+
Assert.True(set.Remove(new List<int>(new[] { 1, 2, 3 })));
38+
}
39+
}
40+
}
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
using System;
2+
using Xunit;
3+
using async_enumerable_dotnet;
4+
using System.Threading.Tasks;
5+
using System.Collections.Generic;
6+
7+
namespace async_enumerable_dotnet_test
8+
{
9+
public class ToListTest
10+
{
11+
[Fact]
12+
public async void Normal()
13+
{
14+
await AsyncEnumerable.Range(1, 5)
15+
.ToList()
16+
.AssertResult(new List<int>(new[] { 1, 2, 3, 4, 5 }));
17+
}
18+
19+
[Fact]
20+
public async void Empty()
21+
{
22+
await AsyncEnumerable.Empty<int>()
23+
.ToList()
24+
.AssertResult(new List<int>());
25+
}
26+
27+
[Fact]
28+
public async void Error()
29+
{
30+
await AsyncEnumerable.Error<int>(new InvalidOperationException())
31+
.ToList()
32+
.AssertFailure(typeof(InvalidOperationException));
33+
}
34+
}
35+
}

0 commit comments

Comments
 (0)