C# Programming Practices – How to Implement Dynamic Dimension for Loops

cprogramming practices

I have a for loop in C# as below,

int[] dim1, dim2, dim3;
//Initialize dim1, dim2 and dim3
for(int i = 0; i < dim1.Length; i++)
{   
    DoSomething1(i);
    for(int j = 0; j < dim2.Length; j++)
    {
        DoSomething2(i, j);
        for(int k = 0; k < dim3.Length; k++)
        {
            DoSomething3(i, j, k);
        }    
    }
}

My problem is that sometimes the dimension of array dim2 would be 0, then DoSomething2() and DoSomething3() will not be executed. Is there any way to bypass the second for loop if dim2.Length = 0? That is, when dim2.Length = 0, I want the whole for loops to behave like below,

int[] dim1, dim2, dim3;
//Initialize dim1, dim2 and dim3
for(int i = 0; i < dim1.Length; i++)
{   
    DoSomething1(i);

    for(int k = 0; k < dim3.Length; k++)
    {
        DoSomething3(i, k);
    }    
}

Moreover, the for loops might be many dimensions (I will have dim1, dim2, dim3, dim4, …, dimn), and except for the length of dim1, the length of any other array might be 0. Is there any good way to do this?
Thanks!

Best Answer

Since the logic you want to execute is conceptually the same for every "dimension", and the only thing that varies is the array you loop over and the function you call in that loop, I'd simply use a recursive function which takes array and function arguments. I don't know C# all that well, but I assume the core of that approach would look something like this:

public delegate void IntConsumer(List<int> ints);

public static void doStuff(List<List<int>> arrays, List<IntConsumer> consumers) {
    processArrays(arrays, consumers, new List<int>());
}

private static void processArrays(List<List<int>> arrays,
                                  List<IntConsumer> consumers,
                                  List<int> consumerArgsSoFar) {
    if(consumers.Count == 0 || arrays.Count == 0) {
        return;
    }

    List<int> currentArray = arrays[0];
    List<List<int>> remainingArrays = arrays.GetRange(1, arrays.Count-1);
    IntConsumer currentConsumer = consumers[0];
    List<IntConsumer> remainingConsumers = consumers.GetRange(1, arrays.Count-1);

    if(currentArray.Count == 0) {
        processArrays(remainingArrays, remainingConsumers, consumerArgsSoFar);
    } else {
        for(int i = 0; i < currentArray.Count; i++) {
            List<int> consumerArgs = new List<int>(consumerArgsSoFar);
            consumerArgs.Add(currentArray[i]);

            currentConsumer(consumerArgs);

            processArrays(remainingArrays, remainingConsumers, consumerArgs);
        }
    }
}

Complete, working version of this example: https://ideone.com/HXrIXd

Now the number of dimensions is entirely up to the caller of doStuff(), without the caller having to manage any of this "skipping empty dimensions" logic. I assume that's what you were looking to achieve, based on your comment on Mason's answer.

Related Topic