Creating N nested for-loops

10,182

Solution 1

You may use recursion instead with a base condition -

void doRecursion(int baseCondition){

   if(baseCondition==0) return;

   //place your code here

   doRecursion(baseCondition-1);
}  

Now you don't need to provide the baseCondition value at compile time. You can provide it while calling the doRecursion() method.

Solution 2

Here is a nice little class for a multi-index that can be iterated via a range-based for-loop:

#include<array>

template<int dim>
struct multi_index_t
{
    std::array<int, dim> size_array;
    template<typename ... Args>
    multi_index_t(Args&& ... args) : size_array(std::forward<Args>(args) ...) {}

    struct iterator
    {
        struct sentinel_t {};

        std::array<int, dim> index_array = {};
        std::array<int, dim> const& size_array;
        bool _end = false;

        iterator(std::array<int, dim> const& size_array) : size_array(size_array) {}

        auto& operator++()
        {
            for (int i = 0;i < dim;++i)
            {
                if (index_array[i] < size_array[i] - 1)
                {
                    ++index_array[i];
                    for (int j = 0;j < i;++j)
                    {
                        index_array[j] = 0;
                    }
                    return *this;
                }
            }
            _end = true;
            return *this;
        }
        auto& operator*()
        {
            return index_array;
        }
        bool operator!=(sentinel_t) const
        {
            return !_end;
        }
    };

    auto begin() const
    {
        return iterator{ size_array };
    }
    auto end() const
    {
        return typename iterator::sentinel_t{};
    }
};

template<typename ... index_t>
auto multi_index(index_t&& ... index)
{
    static constexpr int size = sizeof ... (index_t); 
    auto ar = std::array<int, size>{std::forward<index_t>(index) ...};
    return multi_index_t<size>(ar);
}

The basic idea is to use an array that holds a number of dim indices and then implement operator++ to increase these indices appropriately.

Use it as

for(auto m : multi_index(3,3,4))
{
    // now m[i] holds index of i-th loop
    // m[0] goes from 0 to 2
    // m[1] goes from 0 to 2
    // m[2] goes from 0 to 3
    std::cout<<m[0]<<" "<<m[1]<<" "<<m[2]<<std::endl;
}

Live On Coliru

Solution 3

You could use a recursive function:

void loop_function(/*params*/,int N){
for(int i=0;i<9;++i){
    if(N>0) loop_function(/*new params*/,N-1);
}

This will call recursively to loop_function N times, while each function will iterate calling loop_function

It may be a bit harder to program this way, but it should do what you want

Solution 4

You can use recursive call as:

void runNextNestedFor(std::vector<int> counters, int index)
{
     for(counters[index] = 0; counters[index] < 9; ++counters[index]) {
       // DO
       if(index!=N)
          runNextNestedFor(counters, index+1);
     }
}

Call it first time as:

std::vectors<int> counters(N);
runNextNestedFor(counters, 0);

Solution 5

I'm going to take the OP at face value on the example code that was given, and assume what's being asked for is a solution that counts through an arbitrary base-10 number. (I'm basing this on the comment "Ideally I'm trying to figure out a way to loop through seperate elements of a vector of digits to create each possible number".

This solution has a loop that counts through a vector of digits in base 10, and passes each successive value into a helper function (doThingWithNumber). For testing purposes I had this helper simply print out the number.

#include <iostream>

using namespace std;

void doThingWithNumber(const int* digits, int numDigits)
{
    int i;
    for (i = numDigits-1; i>=0; i--)
        cout << digits[i];
    cout << endl;
}

void loopOverAllNumbers(int numDigits)
{
    int* digits = new int [numDigits];
    int i;
    for (i = 0; i< numDigits; i++) 
        digits[i] = 0;

    int maxDigit = 0;
    while (maxDigit < numDigits) {
        doThingWithNumber(digits, numDigits);
        for (i = 0; i < numDigits; i++) {
            digits[i]++;
            if (digits[i] < 10)
                break;
            digits[i] = 0;
        }
        if (i > maxDigit)
            maxDigit = i;
    }
}

int main()
{
    loopOverAllNumbers(3);
    return 0;
}
Share:
10,182
Andrew
Author by

Andrew

Updated on August 20, 2022

Comments

  • Andrew
    Andrew over 1 year

    Is there a way to create for-loops of a form

    for(int i = 0; i < 9; ++i) {
        for(int j = 0; j < 9; ++i) {
        //...
            for(int k = 0; k < 9; ++k) { //N-th loop
    

    without knowing N at the compile time. Ideally I'm trying to figure out a way to loop through separate elements of a vector of digits to create each possible number if a certain amount of digits is replaced with different digits.

  • Andrew
    Andrew almost 9 years
    Why is there a gap between if ans else? I'm not sure how it can work out
  • Andrew
    Andrew almost 9 years
    When I try run int counter = 0; void loop_function(vector<int>& digits,int n) { int index = n-1; for(digits[index] = 0; digits[index] < 9; ++digits[index]) { if(n>1) loop_function(digits, n-1); display(digits); ++counter; } } int main() { vector<int> vec(3, 0); loop_function(vec, vec.size()); cout << counter << endl; return 0; } I get counter = 819, but surely its meant to be 999?
  • Andrew
    Andrew almost 9 years
    What's the reason for holding min_ind and max_ind in vectors? Wouldn't it be easier just to use int min_ind and int max_ind?
  • angrykoala
    angrykoala almost 9 years
    As i understand your code, your vector digits are changing until the vector is {9,9,9}, to do this, you perform 9*9*9 iterations on the last element (you go from 0 to 9 inside 2 loops), for the second you do 9*9 iterations, and for the last 9 more iterations. So, finally, you have the digits vector to {9,9,9}, and to get that, you perform a total of 9*9*9+9*9+9=819 iterations, which is the counter you said
  • Andrew
    Andrew almost 9 years
    I'm trying to create every element from 1 to 999. What do I need to change in the code?
  • angrykoala
    angrykoala almost 9 years
    each time you call to the function you are restarting that position element i don't understand what you want, if you want to get {999,999,999} in the minimun iterations (2997) nested loops don't seems like a good choice, as you are over complicating the problem, if you want to do like you are doing (resulting in 998001999 iterations) just change 9 for 999, but obviously it won't be a good idea. When you are nesting loops, the final loop will iterate n times more than previous, so if you don't restart the count and leave it how it is, you will get {9,81,719} as result in 819 iterations
  • Razib
    Razib almost 9 years
    @Andrew, Thanks. I have fixed it. Actually at first there was not the comment (//place your code here) portion there. After adding the comment I forget to remove the else.
  • davidhigh
    davidhigh almost 9 years
    if that suffices for you, do it like this. It could however be that the first loop shall go from 3 to 6, the second from 1 to 8 and so on.
  • Luke Rodgers
    Luke Rodgers over 7 years
    Good answer! Plug-n-play for me.