我要生成的字符串列表的所有可能组合的列表(它实际上是对象的列表,但为了简单起见,我们将使用字符串)。 我需要这个名单,这样我可以在一个单元测试测试每一个可能的组合。
因此,举例来说,如果我有一个列表:
var allValues = new List<string>() { "A1", "A2", "A3", "B1", "B2", "C1" }
我需要一个List<List<string>>
与像所有的组合:
A1
A2
A3
B1
B2
C1
A1 A2
A1 A2 A3
A1 A2 A3 B1
A1 A2 A3 B1 B2
A1 A2 A3 B1 B2 C1
A1 A3
A1 A3 B1
etc...
递归函数是可能做到这一点得到所有组合的方式,但它似乎比我想象的更难。
任何指针?
谢谢。
编辑:两种解决方案,带或不带递归:
public class CombinationGenerator<T>
{
public IEnumerable<List<T>> ProduceWithRecursion(List<T> allValues)
{
for (var i = 0; i < (1 << allValues.Count); i++)
{
yield return ConstructSetFromBits(i).Select(n => allValues[n]).ToList();
}
}
private IEnumerable<int> ConstructSetFromBits(int i)
{
var n = 0;
for (; i != 0; i /= 2)
{
if ((i & 1) != 0) yield return n;
n++;
}
}
public List<List<T>> ProduceWithoutRecursion(List<T> allValues)
{
var collection = new List<List<T>>();
for (int counter = 0; counter < (1 << allValues.Count); ++counter)
{
List<T> combination = new List<T>();
for (int i = 0; i < allValues.Count; ++i)
{
if ((counter & (1 << i)) == 0)
combination.Add(allValues[i]);
}
// do something with combination
collection.Add(combination);
}
return collection;
}
}
您可以手动在,使用n位二进制数自然会对应于n元素集合的子集的事实。
private IEnumerable<int> constructSetFromBits(int i)
{
for (int n = 0; i != 0; i /= 2, n++)
{
if ((i & 1) != 0)
yield return n;
}
}
List<string> allValues = new List<string>()
{ "A1", "A2", "A3", "B1", "B2", "C1" };
private IEnumerable<List<string>> produceEnumeration()
{
for (int i = 0; i < (1 << allValues.Count); i++)
{
yield return
constructSetFromBits(i).Select(n => allValues[n]).ToList();
}
}
public List<List<string>> produceList()
{
return produceEnumeration().ToList();
}
如果你想所有的变化,看看这个项目,看看它是如何实现的。
http://www.codeproject.com/Articles/26050/Permutations-Combinations-and-Variations-using-CG
但因为它是根据开源,你可以用它CPOL 。
例如:
var allValues = new List<string>() { "A1", "A2", "A3", "B1", "B2", "C1" };
List<String> result = new List<String>();
var indices = Enumerable.Range(1, allValues.Count);
foreach (int lowerIndex in indices)
{
var partVariations = new Facet.Combinatorics.Variations<String>(allValues, lowerIndex);
result.AddRange(partVariations.Select(p => String.Join(" ", p)));
}
var length = result.Count; // 1956
还有一个递归解决方案。 从AllCombinations
在下面的代码,你会得到所有可能的组合。 逻辑:
- 一个元素开始。
- 生成与它所有可能的组合。
- 移动到下一个元素,并与第2步重新开始。
码:
public class Combination<T>
{
private IEnumerable<T> list { get; set; }
private int length;
private List<IEnumerable<T>> _allCombination;
public Combination(IEnumerable<T> _list)
{
list = _list;
length = _list.Count();
_allCombination = new List<IEnumerable<T>>();
}
public IEnumerable<IEnumerable<T>> AllCombinations
{
get
{
GenerateCombination(default(int), Enumerable.Empty<T>());
return _allCombination;
}
}
private void GenerateCombination(int position, IEnumerable<T> previousCombination)
{
for (int i = position; i < length; i++)
{
var currentCombination = new List<T>();
currentCombination.AddRange(previousCombination);
currentCombination.Add(list.ElementAt(i));
_allCombination.Add(currentCombination);
GenerateCombination(i + 1, currentCombination);
}
}
}