Мое решение использует простой рекурсивный алгоритм для создания комбинаций:
Когда мы идем через последовательность мы можем немедленно возвратить последовательность, которая содержит только текущее значение. Я написал простой метод расширения для создания IEnumerable для одного элемента.
Далее мы рекурсивно генерируем все комбинации для остальных элементов с порогом, уменьшенным на 1, и объединяем каждое из них с текущим значением.
Я предполагаю, что элементы не должны повторяться (т. Е. {1, 1} или {1, 2, 1} не допускаются). Если вы хотите разрешить повторяющиеся элементы, вы можете удалить переменную remaining
и заменить ее values
на рекурсивный вызов GetCombinations
.
Обратите внимание на использование ключевого слова yield
. Это означает, что код использует отложенное выполнение. Нет необходимости хранить промежуточные результаты до фактического перечисления результата.
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;
}
Для массива целых чисел {1, 2, 3, 4, 5} выход:
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
Ваш вопрос очень похож на http://stackoverflow.com/q/774457/ 2145211. Вы смотрели ответы там? – Harrison