当我处理多种数据类型时,如何处理多个foreach循环

时间:2015-05-15 15:42:48

标签: c# loops

我有一个困扰我一段时间的问题,它关注我程序中循环的增长呈指数级增长。我将让下面的代码进行讨论并在其中添加注释。

void Main()
{
    //Here we are just creating simple lists
    List<string> strings = new List<string>();
    strings.Add("a");
    strings.Add("b");
    strings.Add("c");

    List<int> integers = new List<int>();
    integers.Add(1);
    integers.Add(2);
    integers.Add(3);

    //Creating complex classes ( not really )
    ComplexClass cc1 = new ComplexClass();
    cc1.CCString = "A test";
    cc1.CCInt = 2;

    ComplexClass cc2 = new ComplexClass();
    cc2.CCString = "Another test";
    cc2.CCInt = 6;

    //Creating a list of these too
    List< ComplexClass > complexClasses = new List< ComplexClass >();
    complexClasses.Add(cc1);
    complexClasses.Add(cc2);


    //Here i want to create every possible combination using each of the lists 
    //and then add these to a testData class to do other things with, serialize, save, print etc.
    //The main question is here, the for loops will definitely increase exponentially with each
    //list added to. 
    foreach( int i in integers )
    {
        foreach( string s in strings )
        {
            foreach( ComplexClass compClass in complexClasses )
            {
                TestData data = new TestData();
                data.TestInteger = i;
                data.TestString = s;
                data.TestComplexClass = compClass;

                OutPutTestData( data );
            }
        }
    }
}

//Simply outputs the data as test but I will be keeping the object for later also
public void OutPutTestData( TestData testData )
{
    Console.WriteLine( testData.TestString + testData.TestInteger + testData.TestComplexClass.CCString );
}

//The "Complex class" again not that complex but an example of what im tring to achieve
public class ComplexClass
{
    public string CCString{ get; set; }
    public int CCInt { get; set; }
}

//The overall test object which holds multiple properties of different data types
public class TestData
{
    public string TestString { get; set; }
    public int TestInteger { get; set; }
    public ComplexClass TestComplexClass { get; set; }
}

输出

  

a1 Test1

     

a1 Test2

     

b1 Test1

     

b1 Test2

     

c1 Test1

     

c1 Test2

     

a2 Test1

     

a2 Test2

     

b2 Test1

     

b2 Test2

     

c2 Test1

     

c2 Test2

     

a3 Test1

     

a3 Test2

     

b3 Test1

     

b3 Test2

     

c3 Test1

     

c3 Test2

正如您所看到的,循环工作并为我提供所提供数据的所有可能组合。

我的问题是for循环的指数式增长,因为我添加了更多列表。可能有大量的列表。

我确实理解迭代次数会随着组合的发现而增加,这不是问题,因为我计划在估算可能的总迭代次数后,以编程方式限制基于用户输入可能发生的迭代次数。

e.g。总迭代次数为234次,因此只迭代120次(120次组合)

提供的代码适用于嵌套的foreach循环,但随着它呈指数级增长,它变得难以阅读,难以管理并且通常难看。

我已经看过像这样的排列算法:

Algorithm to generate all possible permutations of a list?

Understanding Recursion to generate permutations

但是它们只允许使用一种特定的数据类型而不是多种数据类型。

我也研究过笛卡尔积,但我发现的唯一例子只涉及一种数据类型。

2 个答案:

答案 0 :(得分:4)

即使你选择了一个答案,我想你可能想要看看这个...使用递归,你所要做的就是将所有List放在{{{ 1}}。您只需将新添加的List<IList>添加到List即可。

我为List<IList>添加了override ToString(),以便适合。

ComplexClass

结果(并未捕获所有结果):

enter image description here

答案 1 :(得分:3)

你可以通过在Linq中进行交叉连接来摆脱for循环:

var query = 
    from  i in integers
    from s in strings 
    from compClass in complexClasses
    select new TestData()
    {
        TestInteger = i,
        TestString = s,
        TestComplexClass = compClass
    };

foreach (var data in query)
    OutPutTestData( data );

如果列表都是相同类型,那么可以构建一个交叉加入不同数量列表的查询。在你的情况下,因为列表是不同类型的,所以不可能(没有反射,动态或更丑陋的东西)