Вы можете использовать интегральное значение для подсчета всех комбинаций.
Затем для каждого значения проверьте каждый бит в числе. Каждый бит 1
означает, что соответствующий элемент включен в комбинацию.
Если вы подумаете о том, как работают двоичные числа, вы поймете, как работает этот алгоритм. Например, для 3 элементов у вас будет 3-битное двоичное число, которое идет от 001 до 111, причем каждый из 3 битов соответствует одному из элементов, например:
001
010
011
100
101
110
111
Вы должны увидеть, как мы можем использовать каждый бит, чтобы решить, включен ли соответствующий элемент в эту комбинацию.
Вот пример реализации - это работает, если количество элементов <= 32: </p>
public static IEnumerable<IEnumerable<T>> Combinations<T>(IList<T> items)
{
return Combinations(items.Count).Select(comb => comb.Select(index => items[index]));
}
public static IEnumerable<IEnumerable<int>> Combinations(int n)
{
long m = 1 << n;
for (long i = 1; i < m; ++i)
yield return bitIndices((uint)i);
}
static IEnumerable<int> bitIndices(uint n)
{
uint mask = 1;
for (int bit = 0; bit < 32; ++bit, mask <<= 1)
if ((n & mask) != 0)
yield return bit;
}
Вы можете проверить это, например, с помощью списка символов A..E:
IList<char> test = "ABCDE".ToList();
foreach (var comb in Combinations(test))
Console.WriteLine(string.Concat(comb));
Это выводит:
A
B
AB
C
AC
BC
ABC
D
AD
BD
ABD
CD
ACD
BCD
ABCD
E
AE
BE
ABE
CE
ACE
BCE
ABCE
DE
ADE
BDE
ABDE
CDE
ACDE
BCDE
ABCDE
Если вы хотите превратить IEnumerable<IEnumerable<T>>
в List<List<T>>
, просто сделайте следующее:
List<List<T>> list = Combinations(inputList).Select(x => x.ToList()).ToList();
Например, для List<char>
выше:
List<List<char>> list = Combinations(test).Select(x => x.ToList()).ToList();