My solution uses a simple recursive algorithm to create the combinations:
When we walk through the sequence we can immediately return a sequence that only holds the current value. I have written a simple extension method to create an IEnumerable for a single item.
Next we recursively generate all combinations for the remaining elements with the threshold reduced by 1 and combine each of them with the current value.
I assume that elements should not be repeated (i.e. { 1, 1 } or { 1, 2, 1 } are not allowed). If you want to allow repeated elements you can remove the remaining
variable and replace it with values
in the recursive call to GetCombinations
.
Please note the use of the yield
keyword. This means that the code uses deferred execution. There is no need to store any intermediate results before you actually enumerate the result.
public static IEnumerable<IEnumerable<T>> GetCombinations<T>(IEnumerable<T> values, int threshold)
{
var remaining = values;
foreach (T value in values)
{
yield return value.Yield();
if (threshold < 2)
{
continue;
}
remaining = remaining.Skip(1);
foreach (var combination in GetCombinations(remaining, threshold - 1))
{
yield return value.Yield().Concat(combination);
}
}
}
public static IEnumerable<T> Yield<T>(this T item)
{
yield return item;
}
For the integer array { 1, 2, 3, 4, 5 } the output is:
1
1, 2
1, 2, 3
1, 2, 4
1, 2, 5
1, 3
1, 3, 4
1, 3, 5
1, 4
1, 4, 5
1, 5
2
2, 3
2, 3, 4
2, 3, 5
2, 4
2, 4, 5
2, 5
3
3, 4
3, 4, 5
3, 5
4
4, 5
5