【问题标题】:Multi dimentionnal for loop多维for循环
【发布时间】:2021-05-01 16:56:57
【问题描述】:

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

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 循环。

【问题讨论】:

  • 你的循环在做什么?
  • 使用单个迭代器。由于您循环 31 * 74 * 12 * 15 次,您可以只使用一个循环并通过除法和模运算来计算其他值。
  • 它可以遍历张量(如图)

标签: c for-loop syntax


【解决方案1】:

没有简单的方法,但您可以实现一个类似迭代器的类型,在 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。)

【讨论】:

  • 不错。可能值得注意的是,如果您的循环中有break,则调用combo_reset() 可能很重要。
  • 我喜欢你的方法,它更像是python中用于catesian产品的next()对象迭代器
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-09-02
  • 2017-03-07
  • 2012-04-18
  • 2013-04-30
相关资源
最近更新 更多