使用递归的循环的未知数

时间:2011-12-12 15:38:36

标签: c# recursion

我之前做了一些研究并找到了一些很棒的文章,但我似乎无法为我给出的问题量身定做任何解决方案。从完成的研究中,我认为解决这个问题的最佳方法是使用递归。我已经使用一些泛型类做了一个例子,但基本上我的问题是我在列表中有大约10个类。我可能只有这些课程中的一个,我可能有十个。对于给定的问题,我最终找到了“项目”(所有这些都继承自项目)的最佳组合。我认为这很容易,除非我必须在每次测试之前处理创建组合。

下面是一些仅使用两个类的示例代码。如果递归不是解决此问题的最佳方法,请根据需要进行更正。我如何将其转换为用于测试所需的任意数量的项目?

编辑:正如一些人已经指出我的示例代码是迭代解决方案,但它只有在我有两个项目时才有用。因此,我需要定义一个递归函数来根据运行时所需的for循环次数来解决问题。

-Chance

研究:

C#: N For Loops

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();
            }
        }
    }

3 个答案:

答案 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);
}