如何为嵌套循环设置变量?

时间:2014-09-11 11:07:53

标签: algorithm matlab loops

我想编写一个函数,它接受函数将执行的嵌套循环的数量作为输入。例如,如果输入参数为3,则该函数将执行3个嵌套循环,如下所示:

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

如果输入参数是2,则它将是这样的:

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

如何实施此算法?

7 个答案:

答案 0 :(得分:3)

如上所述,这个问题通常可以通过递归来解决。

不知怎的这样:

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

如果您不想承担传递remainingParamsloopVars的费用,可以考虑将其声明为global,但通常最好避免这种情况......

答案 1 :(得分:2)

您可以将所有循环“打包”到一个循环中。以下代码假定

  • 所有循环的上限相同;
  • 你只想在最里面的循环中做事。

Matlab代码:

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

关键是使用通用计数器并从中计算计数器ij等。这是在Matlab中使用dec2base(...)-'0'完成的。 -'0'部分是必需的,因为dec2base返回一个char数组,因此-'0'将每个char转换为它所代表的数字。在其他语言中,它可能会有不同的做法,但你明白了。

答案 2 :(得分:1)

您可以使用单个平坦循环并在一个被视为里程表的数组中跟踪循环变量:通过增加最里面的变量来提前循环,根据需要重置并转移到下一个外部变量。当进位超出你的嵌套pasudo循环数时,停止循环。

这是C中的一个带有无限平坦循环的解决方案,它使用辅助功能来推进循环变量并测试里程表溢出:

#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, e.g. 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;
}

(函数odo_init是必需的,因为无法使用ix[n] = {0}初始化变长数组。)


如果您不介意C预处理器宏的默默无闻,您可以使用此框架编写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))

宏观无比笨拙。它通过标记粘贴创建本地循环变量数组ix和两个隐藏变量。外部for循环正好用于正确初始化循环变量数组。 do ... while已被重写为for,因此您可以像常规for循环一样调用宏:

int main()
{    
    int N = 4;

    multi_for(ix, 2, N) {
        int i;

        /* Do something, e.g. print loop vars */
        for (i = 0; i < N; i++) {
            if (i) printf(", ");
            printf("%d", ix[i]);
        }
        printf("\n");
    }

    return 0;
}

要使其正常工作,您必须更改odo_init以返回0:

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

这个宏依赖于在for和可变长度数组中定义变量,因此需要C99。

答案 3 :(得分:1)

这可能适合你。

但是,有一些假设。  1.你只能在最里面的循环中执行某些操作。  2.所有嵌套循环都有相同的上限

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);
}

答案 4 :(得分:0)

使用递归实现起来并不困难,尽管它似乎仍然是一个奇怪的用例 无论如何,这使得代码尽可能地易于理解,同时“无限”地进行编码。扩展*
每个循环都具有它自己的功能(尽管是相同的),就像你在评论中指定的其他答案一样。

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;
}
例如,使用nestedloops(5,10,data);调用5个嵌套循环,每个循环10次迭代。

希望将void* data更改为更合适的内容(我不知道您将要做的工作)。 在操作数据时,循环变量(i,j,k...)由向量提供,因此不是:

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

您将用

替换作品(在本例中为x=i+j
*data += loop_vars[0]+loop_vars[1];

void* data将更改为int* data

而不是循环,你会调用

nestedloops(2,max,&x);

如果您需要澄清,请发表评论。

*不确定编译器是否能够对此执行tail call elimination,否则,您受到堆栈深度的限制。但是我认为500(GCC默认)是足够的嵌套循环开始,它可以配置得更高,但我再也不知道你的用例,运行时间会得到在这一点之前是恐怖的。

答案 5 :(得分:0)

您可以使用meshgrid生成所有组合。

例如,考虑一个长度未知的向量limits,其中每个循环都应该执行for idx_k = 1:limit(k)。然后

 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         

答案 6 :(得分:-2)

您已使用Mathlab和C ++标记了您的问题。你需要哪一个?这是用C ++编写的。

如果我正确理解你的问题(n个上限为m的循环),那么你需要:

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
    }
}

上面的代码假设您不需要单独的控制变量(i,j,k等)。