How to set a variable for nested loops?

I would like to write a function that takes as input an amount of nested loops that will execute functions. For example, if the input parameter is 3, the function will execute 3 nested loops as follows:

for i=0:[any] for j=0:[any] for k=0:[any] 

and if the input parameter is 2, it will look like this:

 for i=0:[any] for j=0:[any] 

How to implement this algorithm?

+6
source share
7 answers

As mentioned above, this problem can usually be solved by recursion.

Something like this:

 function res = nestedloop_function(numLoops,remainingParams) res = rec_function(numLoops,[],remainingParams); end function res = rec_function(numLoops, loopVars, remainingParams) if numLoops == 0 res = whatever(loopVars, remainingParams); return res; end for k = 1:[any] loopVars = [loopVars,k]; res = rec_function(numLoops-1, loopVars, remainingParams); end end 

If you don't want to have the overhead of going through the remainingParams and loopVars , you might consider declaring them as global , but it is often better to avoid this ...

+3
source

You can pack all the loops in one loop. The following code assumes that

  • The upper limit of all loops is the same;
  • You just want to make stuff in the innermost loop.

Matlab Code:

 N = 3; %// number of loops M = 10; %// range for each variable is from 0 to M-1 for generalCounter = 0:M^N-1 counters = dec2base(generalCounter,M,N)-'0'; %// Now you are at the innermost "loop". counters(1) is your "i", %// counters(2) is your "j" etc end 

The key is to use a common counter and from that count the counters i , j , etc. This is done in Matlab with dec2base(...)-'0' . The -'0' necessary because dec2base returns a char array, so -'0' converts each char to the number it represents. In other languages, this can be done differently, but you get the idea.

+2
source

You can use a single planar contour and track the loop variables in an array that is considered an odometer: Advance the loop by increasing the innermost variable, reloading and moving it to the next outer variable as needed. Stop the loop when the transfer goes beyond your number of nested pasudo loops.

Here's a solution in C with an infinite flat loop that uses a helper function to advance loop variables and check for odometer overflow:

 #include <stdlib.h> #include <stdio.h> void odo_init(int ix[], int n) { while (n--) ix[n] = 0; } int odo(int ix[], int m, int n) { int i = 0; do { ix[i]++; if(ix[i] < m) return 1; ix[i++] = 0; } while (i < n); return 0; } int main() { int m = 2; int n = 4; int ix[n]; odo_init(ix, n); do { int i; /* Do something, eg print loop vars */ for (i = 0; i < n; i++) { if (i) printf(", "); printf("%d", ix[i]); } printf("\n"); /* Advance and test loop variables */ } while(odo(ix, m, n)); return 0; } 

(The odo_init function is optional since variable-length arrays cannot be initialized with ix[n] = {0} .)


If you don't mind the ambiguity of the C preprocessor macros, you can use this framework to write multi_for :

 #define multi_for(ix, m, n) \ for (int ix[n], ix##_cnt_ = 0; \ !(ix##_cnt_ || odo_init(ix, n)); \ ix##_cnt_++) \ for (int ix##_aux_ = 1; \ ix##_aux_; \ ix##_aux_ = odo(ix, m, n)) 

The macro is admittedly awkward. It creates an array of ix local loop variables and two hidden variables when inserting tokens. An external for chain exists only to properly initialize an array of loop variables. do ... while been rewritten as for , so you can call the macro as a regular loop:

 int main() { int N = 4; multi_for(ix, 2, N) { int i; /* Do something, eg print loop vars */ for (i = 0; i < N; i++) { if (i) printf(", "); printf("%d", ix[i]); } printf("\n"); } return 0; } 

For this to work, you must change odo_init to return 0:

 int odo_init(int ix[], int n) { while (n--) ix[n] = 0; return 0; } 

This macro relies on the definition of variables inside for and variable-length arrays, and therefore requires C99.

+1
source

this might work for you.

There are several suggestions. 1. You can only do something in the innermost loop. 2. all nested loops have the same upper limit

 void loop(int n) { if(n < 1) { return; } int i; loop(--n); for( i=0; i<2; i++) { printf("%d", i); //consider this portion to be executing inside the inner most loop } } int main() { int x; int n = 5; //number of for loops you wanted nested loop(n); } 
+1
source

Not too difficult to implement with recursion, although this still seems like a weird use case.
In any case, this makes the code as clear as possible, being "infinitely" extensible *
Each cycle has its own functionality (although it is identical), as you pointed out in the comments to the other answers.

 void do_loop(std::vector<int> *loop_vars, int loop_level, int max_loop_level, int loop_iter_limit, void* data) { while(loop_vars[loop_level] < loop_iter_limit) { //do work on *data *loop_vars[loop_level]++; do_loop(loop_vars, loop_level+1, max_loop_level, loop_iter_limit, data); } else { return; } } void nestedloops(int loop_count, loop_limit, void* data) { std::vector<int> vars; for (int i = 0; i<loop_count; i++) vars.pushback(0); do_loop(&vars, 0, loop_count, loop_limit, data); return; } 

a call using nestedloops(5,10,data); , for example, to execute 5 nested loops with 10 iterations per loop.

You will want to change void* data to something more suitable (I don't know what kind of work you will do). When manipulating data, loop variables ( i,j,k... ) are set by a vector, therefore instead of:

 for (int i = 0; i<max; i++) { for (int j = 0; j<max; j++) { x += i+j; } } 

you would replace the job (in this case x=i+j ) with

 *data += loop_vars[0]+loop_vars[1]; 

void* data will be changed to int* data

and instead of loops you should call

 nestedloops(2,max,&x); 

Please comment if you need clarification.

* not sure if the compiler will be able to perform tail call elimination , if it is not, you are limited by the depth of the stack. However, I think that 500 (GCC by default) has enough nested loops to start with them, and it can be set higher, but again I don’t know your use case, and the execution time will be horrified to this point.

0
source

You can use meshgrid to create all combinations.

Consider, for example, you have a limits vector of unknown length, where each loop must execute for idx_k = 1:limit(k) . Then

  function unknownNested( limts ) n = numel(limits); %// how many neted loops there are range = cell(1,n); %// range for each loop for ii=1:n range(ii) = 1:limits(ii); end [idx{1:n}] = meshgrid( range{:} ); idx = cellfun( @(x) x(:), idx, 'uni', false ); %// "flatten" all ranges allRanges = [idx{:}]; %// now you can loop once over all combinations for ii = 1:size(allRanes,1) counters = allRanges(ii,:); %// now you have an n-vector with the counter of each nested loop %// do you work here... end 
0
source

You noted your question with both Mathlab and C ++. Which one do you need? This is in C ++.

If I understand your question correctly (n loops with an upper limit of m), you need something like:

 void func(int countLoops, int loopUpperLimit) { // simpler code with 2 loops while (countLoops-- > 0) { for (int i = 0; i < loopUpperLimit; i++) { // do something } } // shorter code with one loop for (int i = 0, limit = loopUpperLimit * countLoops; i < limit; i++) { // do something } } 

The code above assumes that you do not need separate control variables (i, j, k, etc.).

-2
source

Source: https://habr.com/ru/post/975120/


All Articles