Loops inside loops
I'd like to find easier way to write loops insid开发者_Go百科e loops.
Here is example code of 3 levels of 'for' loops:int level = 0;
int value = 0;
bool next = false;
for (int i0 = 0; i0 < 6; i0++)
{
level = 0;
value = i0;
method();
if (next)
for (int i1 = 0; i1 < 6; i1++)
{
level = 1;
value = i1;
method();
if (next)
for (int i2 = 0; i2 < 6; i2++)
{
level = 2;
value = i2;
method();
if (next)
{
//Do somethnig
}
}
}
}
private void method()
{
//use int 'level' and 'value'
//determine bool 'next'
}
I wonder if it's possible to write the same thing different way. To set number of levels(number of loops) and loop repeats. In this case levels = 3; repeats = 6;. I need it because I am using more than 20 loops inside themselves and than the code is not comprehensible.
I hope my explanation was ok and thanks for help.
Go go gadget recursion!
public static void Loopy(int level, int maxLevel, int repeat)
{
if (level > maxLevel)
return;
for (int i = 0; i < repeat; i++)
{
if (SomeMethod(level, i);)
Loopy(level + 1, maxLevel, repeat);
}
}
public static bool SomeMethod(int level, int i)
{
Console.WriteLine("level: {0}, i: {1}", level, i);
return ...
}
Instead of loop use recursive call:
void recursiveCall(int currentLevel)
{
if (currentLevel == 0)
return;
for (int i0 = 0; i0 < 6; i0++)
{
level = 0;
value = i0;
method();
if (next)
recursiveCall(currentLevel - 1);
}
}
You could use recursion in this case:
public void doLevel(int level)
{
for (int i = 0; i < 6; i++)
{
if(method(i, level))
doLevel(level +1);
}
}
private bool method(int value, int level)
{
//use int 'level' and 'value'
//determine bool 'next'
}
Are you looking for backtracking? 20 inner loops seems a bit excessive for anything else...
Note that the following isn't a complete solution to what you asked. Also, a recursion-based solution is probably more appropriate. However, I'm posting this answer as a possible alternate way of thinking about the problem.
What you could do to get rid of the loops is to calculate the "cross product" of the values of i0
, i1
, and i2
as follows:
foreach (var i in from i0 in Enumerable.Range(0, 6)
from i1 in Enumerable.Range(0, 6)
from i2 in Enumerable.Range(0, 6)
select Tuple.Create(i0, i1, i2))
{
// i is now a tuple containing any combination of i0, i1, and i2.
}
(If you need more levels, simply add another from .. in ..
and expand the tuple by passing another argument to Tuple.Create
.)
The tuples will arrive in this order:
[0, 0, 0]
[0, 0, 1]
. . .
[0, 0, 5]
[0, 1, 0]
[0, 1, 1]
. . .
[0, 1, 5]
[1, 0, 0]
[1, 0, 1]
. . .
i.e. the same order as with your nested for
loops.
This half-solution however requires that you change the way your method()
currently works, since calls to that method can't be made "in-between" the tuple components' generation. One possibility might be to derive both level
and value
from the current tuple i
and pass them into method
as arguments. next
could become the return value of method
:
foreach (var i in ...)
{
bool next = method(level: ..., value: ...);
...
}
Again, this is not intended as a final solution, but as a possibility to change around your code.
not very efficient but shorter is to use recursion which gets an array of counters as one parameter and the current level in the array as 2nd param.
then you can do something in the line of
paramsarray= array (4,5,6,3) ; //the depths of loops in each level
current_counts = array (0,0,0,0);
function loop (paramsarray, current_counts, depth){
if (depth> count(paramsarray) && ( index > paramsarray [depth])) return;// end recursion
// Do something here with current_counts as your current loop values
//
current_counts[depth]++
if (current_counts[depth] > paramsarray[depth]) depth++
loop (paramsarray, current_counts, depth)
}
精彩评论