Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Generate combinations of elements held in multiple list of strings in C#

Tags:

c#

.net

I'm trying to automate the nested foreach provided that there is a Master List holding List of strings as items for the following scenario.

Here for example I have 5 list of strings held by a master list lstMaster

            List<string> lst1 = new List<string> { "1", "2" };
            List<string> lst2 = new List<string> { "-" };
            List<string> lst3 = new List<string> { "Jan", "Feb" };
            List<string> lst4 = new List<string> { "-" };
            List<string> lst5 = new List<string> { "2014", "2015" };

            List<List<string>> lstMaster = new List<List<string>> { lst1, lst2, lst3, lst4, lst5 };

            List<string> lstRes = new List<string>();



            foreach (var item1 in lst1)
            {
                foreach (var item2 in lst2)
                {
                    foreach (var item3 in lst3)
                    {
                        foreach (var item4 in lst4)
                        {
                            foreach (var item5 in lst5)
                            {
                                lstRes.Add(item1 + item2 + item3 + item4 + item5);
                            }
                        }
                    }
                }
            }

I want to automate the below for loop regardless of the number of list items held by the master list lstMaster

like image 651
navule Avatar asked Feb 19 '15 15:02

navule


2 Answers

Just do a cross-join with each successive list:

 IEnumerable<string> lstRes = new List<string> {null};
 foreach(var list in lstMaster)
 {
     // cross join the current result with each member of the next list
     lstRes = lstRes.SelectMany(o => list.Select(s => o + s));
 }

results:

List<String> (8 items)
------------------------ 
1-Jan-2014 
1-Jan-2015 
1-Feb-2014 
1-Feb-2015 
2-Jan-2014 
2-Jan-2015 
2-Feb-2014 
2-Feb-2015 

Notes:

  • Declaring lstRes as an IEnumerable<string> prevents the unnecessary creation of additional lists that will be thrown away with each iteration

  • The instinctual null is used so that the first cross-join will have something to build on (with strings, null + s = s)

like image 108
D Stanley Avatar answered Sep 17 '22 14:09

D Stanley


To make this truly dynamic you need two arrays of int loop variables (index and count):

int numLoops = lstMaster.Count;
int[] loopIndex = new int[numLoops];
int[] loopCnt = new int[numLoops];

Then you need the logic to iterate through all these loopIndexes.

Init to start value (optional)

for(int i = 0; i < numLoops; i++) loopIndex[i] = 0;
for(int i = 0; i < numLoops; i++) loopCnt[i] = lstMaster[i].Count;

Finally a big loop that works through all combinations.

bool finished = false;
while(!finished)
{
     // access current element
     string line = "";
     for(int i = 0; i < numLoops; i++)
     {
         line += lstMaster[i][loopIndex[i]];
     }
     llstRes.Add(line);
     int n = numLoops-1;                  
     for(;;)
     {
         // increment innermost loop
         loopIndex[n]++;
         // if at Cnt: reset, increment outer loop
         if(loopIndex[n] < loopCnt[n]) break;

         loopIndex[n] = 0;
         n--;
         if(n < 0)
         { 
             finished=true;
             break;
         }
     }       
}
like image 32
DrKoch Avatar answered Sep 21 '22 14:09

DrKoch