多维for循环

Multi dimentionnal for loop

有没有简单的方法来转换这个

for (int i=0; i < 31; i++)
    for (int j=0; j < 74; j++)
        for (int k=1; k < 12; k++)
            for (int l=13; l < 15; l++)
                ...

更简单一点

mfor (int start[]={0,0,1,13}; int max[]={31,74,12,15}) {
    printf("%i %i\n", start[1], start[3]);
}

有没有宏或者插件之类的?

这个循环可以迭代思想张量(如图像)来做张量卷积或池化之类的事情。任意维度(可大于4)

或者如何向 C 添加一些语法。我有 mfor 循环的实现。因为 for 循环实际上是一个 while 循环。

没有简单的方法,但您可以实现类似迭代器的类型,在给定范围 n 上生成笛卡尔积:

enum {
    MAX = 8
};

typedef struct Combinator Combinator;

struct Combinator {
    size_t index;       // running index of generated numbers
    size_t n;           // number of dimensions
    int data[MAX];      // current combination
    int start[MAX];     // lower and ...
    int end[MAX];       // .. exclusive upper limits
};

/*
 *      Adds a dimensin with valid range [start, end) to the combinator
 */
void combo_add(Combinator *c, int start, int end)
{
    if (c->n < MAX && start < end) {
        c->data[c->n] = start;
        c->start[c->n] = start;
        c->end[c->n] = end;
        c->n++;
    }
}

/*
 *      Reset the combinator to the lower limits
 */
void combo_reset(Combinator *c)
{
    c->index = 0;
    memcpy(c->data, c->start, sizeof(c->start));
}

/*
 *      Get the next comnination in c->data. Returns 1 if there
 *      is a next combination, 0 otherwise.
 */
int combo_next(Combinator *c)
{
    size_t i = 0;
    
    if (c->index++ == 0) return 1;
    
    do {
        c->data[i]++;
        if(c->data[i] < c->end[i]) return 1;
        c->data[i] = c->start[i];
        i++;
    } while (i < c->n);
    
    return 0;
}

这实现了一个类似里程表的计数器:它递增第一个计数器。如果它溢出,它会重置它并递增下一个计数器,根据需要移动到下一个计数器。如果最后一个计数器溢出,则停止生成组合。 (第一个组合的索引有点混乱,因此您可以从 while 循环的循环条件控制所有内容。可能有更优雅的方法来解决这个问题。)

像这样使用组合器:

Combinator combo = {0};      // Must initialize with zero

combo_add(&combo, 0, 3);
combo_add(&combo, 10, 12);
combo_add(&combo, 4, 7);

while (combo_next(&combo)) {
    printf("%4zu: [%d, %d, %d]\n", combo.index,
        combo.data[0], combo.data[1], combo.data[2]);
} 

此组合器设计为仅使用一次:创建它,设置范围,然后用尽组合。

如果您 break 退出循环,组合子将保留其状态,以便进一步调用 combo_next 继续您中断的地方。您可以通过调用 combo_reset 重新开始。 (这有点像从文件中读取:通常使用它们的方法是读取所有内容,但您可以rewind。)