Skip to content

Commit 40d7369

Browse files
Added subset extensions.
1 parent a5e1619 commit 40d7369

File tree

1 file changed

+100
-0
lines changed

1 file changed

+100
-0
lines changed

source/Extensions.Subsets.cs

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
using System;
2+
using System.Buffers;
3+
using System.Collections.Generic;
4+
5+
namespace Open.Collections
6+
{
7+
public static partial class Extensions
8+
{
9+
/// <summary>
10+
/// Iteratively updates the buffer with the possible subsets.
11+
/// </summary>
12+
/// <returns>An enumerable that yields the buffer.</returns>
13+
public static IEnumerable<T[]> SubsetsBuffered<T>(this IReadOnlyList<T> source, int count, T[] buffer)
14+
{
15+
if (count < 1)
16+
throw new ArgumentOutOfRangeException(nameof(count), count, "Must greater than zero.");
17+
if (count > source.Count)
18+
throw new ArgumentOutOfRangeException(nameof(count), count, "Must be less than or equal to the length of the source set.");
19+
if (buffer is null)
20+
throw new ArgumentNullException(nameof(buffer));
21+
22+
23+
if (count == 1)
24+
{
25+
foreach (var e in source)
26+
{
27+
buffer[0] = e;
28+
yield return buffer;
29+
}
30+
yield break;
31+
}
32+
var pool = ArrayPool<int>.Shared;
33+
var indices = pool.Rent(count);
34+
try
35+
{
36+
for (int pos = 0, index = 0; ;)
37+
{
38+
for (; pos < count; pos++, index++)
39+
{
40+
indices[pos] = index;
41+
buffer[pos] = source[index];
42+
}
43+
yield return buffer;
44+
do
45+
{
46+
if (pos == 0) yield break;
47+
index = indices[--pos] + 1;
48+
}
49+
while (index > source.Count - count + pos);
50+
}
51+
}
52+
finally
53+
{
54+
pool.Return(indices);
55+
}
56+
}
57+
58+
/// <summary>
59+
/// Iteratively updates a buffer with the possible subsets.
60+
/// </summary>
61+
/// <returns>An enumerable that yields a buffer that is at least the length of the count provided.</returns>
62+
public static IEnumerable<T[]> SubsetsBuffered<T>(this IReadOnlyList<T> source, int count)
63+
{
64+
var pool = ArrayPool<T>.Shared;
65+
var buffer = pool.Rent(count);
66+
67+
try
68+
{
69+
return SubsetsBuffered(source, count, buffer);
70+
}
71+
finally
72+
{
73+
pool.Return(buffer);
74+
}
75+
}
76+
77+
/// <summary>
78+
/// Iteratively updates the provided buffer with the possible subsets of the length of the buffer.
79+
/// </summary>
80+
/// <returns>An enumerable that yields a buffer that is at least the length of the count provided.</returns>
81+
public static IEnumerable<T[]> SubsetsBuffered<T>(this IReadOnlyList<T> source, T[] buffer)
82+
=> SubsetsBuffered(source, buffer.Length, buffer);
83+
84+
85+
/// <summary>
86+
/// Iteratively returns the possible subsets of the source.
87+
/// </summary>
88+
/// <returns>An enumerable that yields each subset.</returns>
89+
public static IEnumerable<T[]> Subsets<T>(this IReadOnlyList<T> source, int count)
90+
{
91+
foreach (var s in SubsetsBuffered(source, count))
92+
{
93+
var a = new T[count];
94+
s.CopyTo(a, 0);
95+
yield return a;
96+
}
97+
}
98+
99+
}
100+
}

0 commit comments

Comments
 (0)