1

For example, you are given an integer n(at compile time). Your task is to creat n nested loops with distinct loop control variables(array[0],array[1]. i,j,k...) and under the scope of all loops, execute statements like :cout<<"Hello, World"<<endl and make the possibility to use all loop control variables(So that logic using loop control variables can be designed).Along with n, other informations like initial value and condition for i'th(0 to n) loop control variable could be provided.Our objective should be to make the process flexible and generic. Is it possible in C or C++ or Java or ....(Popular Programming Languages) ?

A C++ code for n = 3 could be :

for(int i = 0; i<n; i++)
{
    for(int j = 0; j<n; j++)
    {
        for(int k = 0; k<i+j; k++)
        {
            cout<<i*j+k<<endl;
        }
    }
}

For n=4, it could be

for(int i = 0; i<n; i++)
{
    for(int j = 0; j<n; j++)
    {
        for(int k = 0; k<i+j; k++)
        {
            for(int l = 0; l<k+3; l++)
            {
                cout<<i*j+k-l<<endl;
            }

        }
    }
}
Tavij
  • 98
  • 7

6 Answers6

2

Variable nested loops can be implemented similar to an odometer. You have an array of counters and an array of end values if the end values are not the same for all counters. For each loop, the least significant counter is incremented, and when it reaches its end value, it is reset to a starting count, and the next least significant counter is incremented, checked to see if it's reached it's end value and so on.

rcgldr
  • 27,407
  • 3
  • 36
  • 61
  • I agree with the general idea, but the sentence *"For each loop, the least significant counter is incremented, and when it reaches its end value, it is reset to a starting count, and the next least significant counter is incremented, checked to see if it's reached it's end value and so on. "* sounds a bit complicated. Instead of incrementing the least significant counter, I would first determine the index of the least-significant counter which is at-least-2-below-its-end-value. This counter is incremented; more significant counters are not incremented; less significant counters are reset to 0. – Stef May 06 '22 at 09:11
  • @Stef - assume all counters go from 0 to 9, then 90% of the time, only the least significant counter is incremented. Of the remaining 10% of the time, the second to least significant counter is incremented 9% of that 10% of time, while the least significant counter is set back to it's starting value. – rcgldr May 06 '22 at 14:44
0

How about something like this? Not the prettiest, but should do the job of creating n layers of loops where n can be defined at run time. (c++, but works with all your languages if you replace the std::vector)

void func(const std::vector<int*>& controlVars, int remainingLayers) {

    int i = 0;
    controlVars.push_back(&i);
    for (; i < n; ++i) {

        if (remainingLayers == 0) {
            // Read control var vector and do something
        }
        else {
            func(controlVars, remainingLayers - 1);
        }
    }
    controlVars.pop_back();
}
0

This is a use-case for recursion:

void loop(int n, int count = -1) {
    if (count == -1) //Could be helper function too
        count = n;
    else if (count == 1) { //Last loop contains logic
        for (int i = 0; i < n; ++i)
            std::cout << "Hello World!\n"; //To have access to the loop variables,
                                           //make a std::vector
        return; //Stop
    }

    for (int i = 0; i < n; ++i)
        loops(n, count - 1);
}

You can then call it using:

loop(3); //3 Nested for loops
loop(4); //4 Nested for loops

You could also make loop more generic by passing a function pointer to the function that has to get executed.

Rakete1111
  • 47,013
  • 16
  • 123
  • 162
0

For fixed bound, you may do

bool increase(const std::vector<std::size_t>& v, std::vector<std::size_t>& it)
{
    for (std::size_t i = 0, size = it.size(); i != size; ++i) {
        const std::size_t index = size - 1 - i;
        ++it[index];
        if (it[index] > v[index]) {
            it[index] = 0;
        } else {
            return true;
        }
    }
    return false;
}

void iterate(const std::vector<std::size_t>& v)
{
    std::vector<std::size_t> it(v.size(), 0);

    do {
        do_job(it);
    } while (increase(v, it));
}

Demo

For dependent bound, you may adapt it to:

bool increase(const std::vector<std::function<std::size_t()>>& v,
              std::vector<std::size_t>& it)
{
    for (std::size_t i = 0, size = it.size(); i != size; ++i) {
        const std::size_t index = size - 1 - i;
        ++it[index];
        if (it[index] > v[index]()) {
            it[index] = 0;
        } else {
            return true;
        }
    }
    return false;
}

void iterate(std::vector<std::size_t>& it,
             const std::vector<std::function<std::size_t()>>& v)
{
    do {
        do_job(it);
    } while (increase(v, it));
}

with usage similar to:

std::vector<std::size_t> its(3, 0);
std::vector<std::function<std::size_t()>> bounds = {
    []{ return 2; },
    []{ return 3; },
    [&its]{ return its[0] + its[1]; },
};

iterate(its, bounds);

Demo

Jarod42
  • 203,559
  • 14
  • 181
  • 302
0

c++ +11 Have bounded for each loop ( If you intent to use the mentioned looping with arrays )

#include <iostream>
int main()
{
    int fibonacci[] = { 0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89 };
    for (int number : fibonacci) // iterate over array fibonacci
       std::cout << number << ' '; // we access the array element for this iteration through variable number

    return 0;
}
Thinkal VB
  • 189
  • 3
  • 12
  • This looks like just one loop over an array. The OP wants to loop within a loop within a loop – Stef May 06 '22 at 09:13
0

One way to do it would be to have a function template that takes a function (innermost loop body) and some bounds:

// Single loop, end of recursion
template<class Function>
void nested_loop( Function && f, std::size_t k)
{
    for ( std::size_t i = 0; i < k; ++i )
        f(i);
}

// General case, Bounds is expected to be convertible to std::size_t.
template<class Function, class ... Bounds>
void nested_loop( Function && f, std::size_t k, Bounds && ... bounds)
{
    for ( std::size_t i = 0;i < k; ++i )
    {
        // The lambda expression here binds 'i' to the first argument
        // of f.
        nested_loop( 
            [f = std::forward<Function>(f), i](auto && ... args)
            {
                return f(i, args ...);
            },
            bounds ... );
    }
}

Which can be used like this:

nested_loop(
    [](int i, int j) { cout << i << ", " << j << endl; },
    2,4 );

This can be trivially extended to support loop bounds that depend on the iteration variable of the outer loops. To do so, you need to require Bounds to be a callable, and bind the iteration variable to its first argument at every step.

sbabbi
  • 11,070
  • 2
  • 29
  • 57