我之前做了一些研究并找到了一些很棒的文章,但我似乎无法为我给出的问题量身定做任何解决方案。从完成的研究中,我认为解决这个问题的最佳方法是使用递归。我已经使用一些泛型类做了一个例子,但基本上我的问题是我在列表中有大约10个类。我可能只有这些课程中的一个,我可能有十个。对于给定的问题,我最终找到了“项目”(所有这些都继承自项目)的最佳组合。我认为这很容易,除非我必须在每次测试之前处理创建组合。
下面是一些仅使用两个类的示例代码。如果递归不是解决此问题的最佳方法,请根据需要进行更正。我如何将其转换为用于测试所需的任意数量的项目?
编辑:正如一些人已经指出我的示例代码是迭代解决方案,但它只有在我有两个项目时才有用。因此,我需要定义一个递归函数来根据运行时所需的for循环次数来解决问题。
-Chance
研究:
Arbitrary number of nested-loops?
Number of nested loops at runtime
static void Main(string[] args)
{
List<Item> myItem = new List<Item>();
int numberItem1 = 0, numberItem2 = 0;
foreach (var item in myItem)
{
if (item.GetType() == typeof(Item1))
{
numberItem1++;
}
else if (item.GetType() == typeof(Item2))
{
numberItem2++;
}
}
List<Item> testingItems = new List<Item>();
//FirstItem
for (int a = 0; a < numberItem1; a++)
{
for (int b = 0; b <= a; b++)
{
testingItems.Add(new Item1 { });
}
//DoTest()
testingItems.Clear();
//Second Item
for (int c = 0; c < numberItem2; c++)
{
for (int d = 0; d <= a ; d++)
{
testingItems.Add(new Item1 { });
}
for (int e = 0; e <= c; e++)
{
testingItems.Add(new Item2 { });
}
//DoTest()
testingItems.Clear();
}
}
}
答案 0 :(得分:1)
我认为以下内容应该有效。
这要求您构建要测试的项类型的堆栈,以及原始列表中存在的每个堆栈的堆栈数,其中两个堆栈彼此同步。
输入List参数应为空列表。
void RecursiveTest(List<Item> testingItems, Stack<Type> itemTypes, Stack<int> itemCounts)
{
if (itemTypes.Count == 0) { return; }
Type thisType = itemTypes.Pop();
int thisCount = itemCounts.Pop();
List<Item> addedItems = new List<Item>();
for (int i = 0; i <= thisCount; i++)
{
if (i > 0)
{
Item thisItem = (Item)Activator.CreateInstance(thisType);
testingItems.Add(thisItem);
addedItems.Add(thisItem);
}
if (itemTypes.Count == 0)
{
DoTest(testingItems);
}
else
{
RecursiveTest(testingItems, itemTypes, itemCounts);
}
}
foreach(Item addedItem in addedItems)
{
testingItems.Remove(addedItem);
}
itemTypes.Push(thisType);
itemCounts.Push(thisCount);
}
注意:此代码不会输出/测试不包含每种项目类型中至少一种的列表。
第二个注释:现在包括遗漏的案例。但是,它也会测试空列表。
答案 1 :(得分:1)
修改
此代码应生成项目列表的所有可能的测试排列+每个测试中应出现的每个项目的最大数量。
示例:myItem = Item1 Item1 Item2 Item2 Item3 tests = 1,0,0; 2,0,0; 0,1,0; 1,1,0; 2,1,0; 0,2,0; 1,2,0; 2,2,0; 0,0,1; 1,0,1; 2,0,1; 0,1,1; 1,1,1; 2,1,1; 0,2,1; 1,2,1; 2,2,1
List<Item> myItem = new List<Item>();
List<Type> myOrder = new List<Item>();
Dictionary<Type, int> myCount = new Dictionary<Type, int>();
foreach (var item in myItem)
{
if (myCount.ContainsKey(item.GetType()))
{
myCount[item.GetType()]++;
}
else
{
myOrder.Add(item.GetType());
myCount.Add(item.GetType(), 1);
}
}
List<Item> testingItems = new List<Item>();
int[] testingCounts = new int[myCount.Count];
while(IncrementCounts(testingCounts, myOrder, myCount)) {
for(int x=0; x<testingCounts.length; x++) {
AddInstances( testingItems, myOrder[x], testingCounts[x] );
}
// doTest()
testingItems.Clear();
}
// count permutations using the maxima
// EXAMPLE: maxima [2, 2, 2]
// 1,0,0; 2,0,0; 0,1,0; 1,1,0; 2,1,0; 0,2,0; 1,2,0; 2,2,0; 0,0,1; 1,0,1; 2,0,1 etc..
public static bool IncrementCounts(int[] counts, List<Type> order, Dictionary<Type, int> maxima) {
for(int x=0; x<counts.length; x++) {
if(counts[x] + 1 <= maxima[order[x]]) {
counts[x]++;
return true;
} else {
counts[x] = 0;
}
}
return false; // overflow, so we're finished
}
public static void AddIstances(List<Item> list, Type type, int count) {
for(int x=0; x<count; x++) {
list.Add( Convert.ChangeType( Activator.CreateInstance(type), type ) );
}
}
请注意,上面的代码是在浏览器窗口中编写的,未经测试,因此可能存在语法错误。
答案 2 :(得分:1)
非递归解决方案。
IEnumerable<List<Item>> TestLists(List<Item> fullList)
{
List<Type> types = fullList.Select(i => i.GetType()).Distinct().ToList();
List<Item> testList = new List<Item> { (Item)Activator.CreateInstance(types[0]) };
yield return testList;
bool finished = false;
while (!finished)
{
bool incremented = false;
int i = 0;
while (i < types.Count && !incremented)
{
if (testList.Where(t => t.GetType() == types[i]).Count() <
fullList.Where(t => t.GetType() == types[i]).Count())
{
testList.Add((Item)Activator.CreateInstance(types[i]));
incremented = true;
}
else
{
testList = testList.Where(t => t.GetType() != types[i]).ToList();
i++;
}
}
if (incremented)
{
yield return testList;
}
else
{
finished = true;
}
}
}
用法:
foreach (var partList in TestLists(myListToTest))
{
DoTest(partList);
}