Skip to content

Commit 0f0b900

Browse files
committed
expose Lookup and implement ApplyResultSelector #87
1 parent 97886cb commit 0f0b900

File tree

2 files changed

+72
-5
lines changed

2 files changed

+72
-5
lines changed

src/ZLinq/Linq/ToLookup.cs

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -315,8 +315,8 @@ void ResizeAndRehash()
315315
}
316316
}
317317

318-
// .NET ILookup implements ICollection
319-
internal sealed class Lookup<TKey, TElement> : ILookup<TKey, TElement>, ICollection<IGrouping<TKey, TElement>>, IReadOnlyCollection<IGrouping<TKey, TElement>>
318+
// .NET ILookup implements ICollection and it is public
319+
public sealed class Lookup<TKey, TElement> : ILookup<TKey, TElement>, ICollection<IGrouping<TKey, TElement>>, IReadOnlyCollection<IGrouping<TKey, TElement>>
320320
{
321321
internal static readonly Lookup<TKey, TElement> Empty = new Lookup<TKey, TElement>();
322322

@@ -325,15 +325,15 @@ internal sealed class Lookup<TKey, TElement> : ILookup<TKey, TElement>, ICollect
325325
readonly int count;
326326
readonly IEqualityComparer<TKey> comparer;
327327

328-
public Lookup() // for empty
328+
Lookup() // for empty
329329
{
330330
this.groups = null;
331331
this.last = null;
332332
this.count = 0;
333333
this.comparer = null!;
334334
}
335335

336-
public Lookup(Grouping<TKey, TElement>[]? groupings, Grouping<TKey, TElement>? last, int count, IEqualityComparer<TKey> comparer)
336+
internal Lookup(Grouping<TKey, TElement>[]? groupings, Grouping<TKey, TElement>? last, int count, IEqualityComparer<TKey> comparer)
337337
{
338338
if (groupings == null)
339339
{
@@ -368,6 +368,24 @@ public IEnumerable<TElement> this[TKey key]
368368

369369
public int Count => count;
370370

371+
// Lookup method
372+
373+
public IEnumerable<TResult> ApplyResultSelector<TResult>(Func<TKey, IEnumerable<TElement>, TResult> resultSelector)
374+
{
375+
ArgumentNullException.ThrowIfNull(resultSelector);
376+
377+
if (last is null) yield break;
378+
var group = last.NextGroupInAddOrder; // as first.
379+
if (group is null) yield break;
380+
381+
var first = group;
382+
do
383+
{
384+
yield return resultSelector(group.Key, group);
385+
group = group.NextGroupInAddOrder;
386+
} while (group != null && group != first);
387+
}
388+
371389
public bool Contains(TKey key)
372390
{
373391
return GetGroup(key) is not null;

tests/ZLinq.Tests/Linq/ToLookupTest.cs

Lines changed: 50 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
1-
namespace ZLinq.Tests.Linq;
1+
using Shouldly;
2+
3+
namespace ZLinq.Tests.Linq;
24

35
public class ToLookupTest
46
{
@@ -261,4 +263,51 @@ public void ICollectionCopyToExceptions()
261263
collection.CopyTo(new IGrouping<int, int>[collection.Count], 1));
262264
}
263265

266+
[Fact]
267+
public void ApplyResultSelector()
268+
{
269+
// Arrange
270+
var xs = new[] { 1, 2, 3, 4, 5, 1, 2, 3 };
271+
var lookup = (ZLinq.Linq.Lookup<int, int>)xs.AsValueEnumerable().ToLookup(x => x % 3);
272+
var expectedLookup = (System.Linq.Lookup<int, int>)xs.ToLookup(x => x % 3);
273+
274+
// Act - transform each group to a string representation
275+
var results = lookup.ApplyResultSelector((key, elements) => $"Key: {key}, Count: {elements.Count()}, Sum: {elements.Sum()}").ToList();
276+
var expectedResults = expectedLookup.ApplyResultSelector((key, elements) => $"Key: {key}, Count: {elements.Count()}, Sum: {elements.Sum()}").ToList();
277+
278+
// Assert
279+
results.Count.ShouldBe(expectedResults.Count);
280+
results[0].ShouldBe(expectedResults[0]);
281+
results[1].ShouldBe(expectedResults[1]);
282+
results[2].ShouldBe(expectedResults[2]);
283+
}
284+
285+
[Fact]
286+
public void ApplyResultSelectorNullSelector()
287+
{
288+
// Arrange
289+
var xs = new[] { 1, 2, 3 };
290+
var lookup = (ZLinq.Linq.Lookup<int, int>)xs.AsValueEnumerable().ToLookup(x => x);
291+
292+
// Act & Assert
293+
Should.Throw<ArgumentNullException>(() =>
294+
{
295+
var result = lookup.ApplyResultSelector<string>(null!).ToList();
296+
});
297+
}
298+
299+
[Fact]
300+
public void ApplyResultSelectorOnEmptyLookup()
301+
{
302+
// Arrange
303+
var xs = Array.Empty<int>();
304+
var lookup = (ZLinq.Linq.Lookup<int, int>)xs.AsValueEnumerable().ToLookup(x => x);
305+
306+
// Act
307+
var results = lookup.ApplyResultSelector((key, elements) => $"Key: {key}, Count: {elements.Count()}").ToList();
308+
309+
// Assert
310+
results.Count.ShouldBe(0);
311+
}
312+
264313
}

0 commit comments

Comments
 (0)