将嵌套的转换为简单的嵌套

时间:2017-09-12 21:33:43

标签: java math

我有一个关于数字生成的新问题,问题从这段代码开始:

for(int i = a1; i<n;i+=s1){
   for(int j = a2; j<m;j+=s2){
      for(int k = a3; k<f;k+=s3){
          ....
             doCalculation(new double[]{i,j,k})

正如你所看到的,我有一些嵌套的for循环,其数字不固定,而且范围是固定的。我想知道是否有一个函数可以将上面的代码转换成类似的东西:

for(int i = 0; i<n*m*f*...;i++){
     doCalculation(evaluateParameters(i))

布鲁斯的回答很好地解决了

doCalculations(0, new int[3], new int[]{1,2,3}, new int[]{7,5,5}, new int[]{2,1,3});

static void doCalculations(int current, int[] params, int[] starts, int[] 
    limits, int[] incrementers) {
    if(current == limits.length) return;
    if(current==0){ // initialize with default values
        params = new int[]{1,2,3};
    }
    for(int i = starts[current]; i <= limits[current]; i += incrementers[current]) {
        int tmp = params[current];
        params[current] = i;

        System.out.println(Arrays.toString(params));

        doCalculations(current + 1, params, starts, limits, incrementers);
        params[current] = tmp;
    }
}

但仍然无效,请参阅输出

[1, 2, 3]
[1, 2, 3]
[1, 2, 3]
[1, 3, 3]
[1, 3, 3]
[1, 4, 3]
[1, 4, 3]
[1, 5, 3]
[1, 5, 3]
[3, 2, 3]
[3, 2, 3]
[3, 2, 3]
[3, 3, 3]
[3, 3, 3]
[3, 4, 3]
[3, 4, 3]
[3, 5, 3]
[3, 5, 3]
...

编辑2:算法的面向对象版本:

public class PriceEntity {

    static void doCalculations(List<SingleParameter> parameters) {
        doCalculations(0, null, parameters);
    }

    static void doCalculations(int current, int[] params, List<SingleParameter> parameters) {
        if(current == parameters.size()) return;
        if(params==null){ // initialize with default values
            params = new int[parameters.size()];
            for (int i = 0; i < parameters.size(); i++) params[i] = parameters.get(i).getStart();
            System.out.println(Arrays.toString(params));
            doCalculations(current, params, parameters);
            return;
        }
        //System.out.println("Current is: "  + current);
        SingleParameter parameterToIncrement = parameters.get(current);
        for(int i = parameterToIncrement.getStart() i <= parameterToIncrement.getStop(); i += parameterToIncrement.getIncrement()) {
            int tmp = params[current];
            params[current] = i;

            System.out.println(Arrays.toString(params));

            doCalculations(current + 1, params, parameters);
            params[current] = tmp;
        }
    }

    public static void main(String[] args) {
        ArrayList <SingleParameter> parameters = new ArrayList<>();
        parameters.add(new SingleParameter(1,5,1));  // 5
        parameters.add(new SingleParameter(2,6,2));  // 3
        parameters.add(new SingleParameter(2,5,3));  // 1
        parameters.add(new SingleParameter(4,12,4)); // 3
        doCalculations(parameters);
    }
}
@Data @NoArgsConstructor @AllArgsConstructor public class SingleParameter {

    private int start, stop, increment;
}

但仍然无效

[1, 2, 2, 4]
[1, 2, 2, 4]
[1, 2, 2, 4]
[1, 2, 2, 4]
[1, 2, 2, 4]
[1, 2, 2, 8]
[1, 2, 2, 12]
[1, 2, 5, 4]
[1, 2, 5, 4]
[1, 2, 5, 8]
[1, 2, 5, 12]
[1, 4, 2, 4]
[1, 4, 2, 4]
[1, 4, 2, 4]
[1, 4, 2, 8]
[1, 4, 2, 12]
[1, 4, 5, 4]
[1, 4, 5, 4]
[1, 4, 5, 8]
[1, 4, 5, 12]
[1, 6, 2, 4]
[1, 6, 2, 4]
[1, 6, 2, 4]
[1, 6, 2, 8]
[1, 6, 2, 12]
...... 140 records

2 个答案:

答案 0 :(得分:2)

如果循环计数未修复,则应使用递归。它可以被调用到任何深度。

void calc(List<Integer> params, int loopsCount, int[] loopLimits)
    int limit = loopLimits[loopsCount];
    for (int i = 0; i < limit; i++) {
        params.add(i);
        if (loopsCount == 0) doCalculation(params)
        else calc(params, loopsCount - 1, loopLimits);
        params.removeLast();
    }
}

当然,你可以在一个for循环中通过一个限制数组limits,使其所有成员相乘,并运行一个循环到最终产品。但是你会失去每个索引的信息,所以你需要计算它并存储在一个临时数组中,例如es

int product = limits[0] * limits[1] * ... * limits[n];
...
int[] indexes = new int[n];
for (i = 0; i < product; i++) {
    doCalculation(indexes);
    increaseIndex = 0;
    while(true) {
         if (indexes[increaseIndex]++ == limits[increaseIndex])
             indexes[increaseIndex++] = 0;
         else break;
    } 
}

但这是不可理解的,也不清楚。但是,可能比递归更快。

答案 1 :(得分:2)

Java for循环不支持在多维结构上循环。

这是一个递归方法,它将模拟n嵌套的for循环。

请注意,params是启动的克隆,因为否则对doCalculation()的第一次调用将传递一个大部分未初始化的数组,在本例中为[4, 0, 0],其中4是第一个元素在starts

int[] starts = new int[]{4, 5, 6};
int[] limits = new int[]{7, 8, 10};
int[] incrementers = new int[]{1, 2, 3}; // elements cannot be <= 0
int[] params = starts.clone(); // must be a clone of starts

doCalculations(starts, limits, incrementers, params, 0);
void doCalculations(int[] starts, int[] limits, int[] incrementers, int[] params, int current) {
    if(current == limits.length) {
        return;
    }
    for(int i = starts[current]; i < limits[current]; i += incrementers[current]) {
        params[current] = i;

        if(current == params.length - 1) {
            doCalculation(params);
        }

        doCalculations(starts, limits, incrementers, params, current + 1);
    }
}
相关问题