dotnet / dotnet/reactive

[Feature] GroupSequentialBy

Open
#2,075 0 comments 0 reactions 0 assignees View on GitHub
[area] Ix
Dominant language
C#
Stars
7.2k
Forks
798
PR merge metrics
No merged PRs in 30d

Description

I believe for async sequences this can be a good addition to `GroupBy` method.
This method would have the same behavior of python's [itertools.groupby](https://docs.python.org/3/library/itertools.html#itertools.groupby)

It's also convenient for asynchronous client-side processing of database query when it's guaranteed that elements of the same group are sequential:
```
return dbContext.Set()
.OrderBy(d => d.DemographicsId)
.ThenBy(d => d.Period.SequenceNumber)
.AsAsyncEnumerable()
.GroupSequentialBy(d => d.Demographics, DemographicsByIdEquality, d => d.Period);
```
Our implementation is the following:
```
///
/// Puts consecutive items of the sequence into groups.
///
///
/// For example, [1,1,2,1] grouped by value will turn into three groups
/// with keys [1,2,1].
///
public static async IAsyncEnumerable> GroupSequentialBy(
this IAsyncEnumerable seq,
Func keySelector, IEqualityComparer keyEqualityComparer,
Func itemSelector)
{
seq.NotNull();
keySelector.NotNull();
keyEqualityComparer.NotNull();
itemSelector.NotNull();

TKey key;
var items = new List();

await using var enumerator = seq.GetAsyncEnumerator();
if (!(await enumerator.MoveNextAsync()))
{
yield break;
}

key = keySelector(enumerator.Current);
items.Add(itemSelector(enumerator.Current));

while (await enumerator.MoveNextAsync())
{
var newKey = keySelector(enumerator.Current);
var newGroupStarted = !keyEqualityComparer.Equals(key, newKey);
var item = itemSelector(enumerator.Current);
if (newGroupStarted)
{
yield return new Grouping(key, items);

items = new List();
}

key = newKey;
items.Add(item);
}

if (items.Count > 0)
{
yield return new Grouping(key, items);
}
}

private sealed class Grouping : IGrouping
{
private readonly TKey _key;
private readonly IEnumerable _elements;

public Grouping(TKey key, IEnumerable elements)
{
_key = key;
_elements = elements.NotNull();
}

public TKey Key => _key;

public IEnumerator GetEnumerator() => _elements.GetEnumerator();

IEnumerator IEnumerable.GetEnumerator() => _elements.GetEnumerator();
}
```

Contributor guide

No contributing guide indexed for this repository

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.