I\'m trying to write an algorithm to select all combinations of n values from a set of numbers.
For instance, given the set: 1, 2, 3, 7, 8, 9
Al
Both answers are good but can be speeded up by eliminating memory allocations
For answer 1: Now 2.5x faster when calculating 5 from 60
Edit: EnumerableEx.Return is from the System.Interactive package.
public static IEnumerable> DifferentCombinations2
(this IEnumerable elements, int k)
{
return k == 0
? EnumerableEx.Return(Enumerable.Empty())
: elements.SelectMany((e, i) =>
elements.Skip(i + 1)
.DifferentCombinations(k - 1)
.Select(c => EnumerableEx.Return(e).Concat(c)));
}
Answer 2: Now 3x faster when calculating 5 from 60
static class Combinations
{
private static void SetIndexes(int[] indexes, int lastIndex, int count)
{
indexes[lastIndex]++;
if (lastIndex > 0 && indexes[lastIndex] == count)
{
SetIndexes(indexes, lastIndex - 1, count - 1);
indexes[lastIndex] = indexes[lastIndex - 1] + 1;
}
}
private static bool AllPlacesChecked(int[] indexes, int places)
{
for (int i = indexes.Length - 1; i >= 0; i--)
{
if (indexes[i] != places)
return false;
places--;
}
return true;
}
public static IEnumerable> GetDifferentCombinations(this IEnumerable c, int count)
{
var collection = c.ToList();
int listCount = collection.Count();
if (count > listCount)
throw new InvalidOperationException($"{nameof(count)} is greater than the collection elements.");
int[] indexes = Enumerable.Range(0, count).ToArray();
do
{
yield return indexes.Select(i => collection[i]).ToList();
SetIndexes(indexes, indexes.Length - 1, listCount);
}
while (!AllPlacesChecked(indexes, listCount));
}
}
This results in answer 2 being 5x faster than answer 1 for 5 from 60.