更改 for 循环的顺序? [英] Change order of for loops?

查看:17
本文介绍了更改 for 循环的顺序?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一种情况,我需要根据用户输入以不同的顺序循环 xyz 坐标.所以我是 3D 空间中的一个区域,然后是一组像这样的 for 循环.

I have a situation where i need to loop though xyz coordinates in different orders depending on a users input. So i an area in 3D space then a set of for loops like so.

for(int x = 0; x < build.getWidth(); x++){
   for(int y = 0; y < build.getHeight(); y++){
     for(int z = 0; z < build.getLength(); z++){
        //do stuff
       }
    }
 }

但是根据用户的输入,顺序可能是这样的.

but depending on the users input, the order may be like this.

for(int z = 0; z < build.getLenght(); z++){
   for(int y = 0; y < build.getHeight(); y++){
     for(int x = 0; x < build.getWidth(); x++){
        //do stuff
       }
    }
 }

甚至是负面的.

for(int x = build.getWidth(); x > 0; x--){
   for(int y = 0; y < build.getHeight(); y++){
      for(int z = 0; z < build.getLength(); z++){
        //do stuff
      }
   }
}

有没有什么办法可以不用硬编码每个案例?

Is there any way to do this without hard coding every case?

推荐答案

这是一个 n 维步进器,它可以按从任何起始位置到任何限制的任何顺序在任意数量的维度上步进.示例请参见测试代码.

Here's an n-dimensional stepper that can step in any number of dimensions in any order from any start locations to any limits. See the test code for an example.

public class Test {
  public void test() {
    int[] limits = {3, -5, 7};
    int[] order = {0, 2, 1};
    int[] starts = {0, 0, 0};
    int[] steps = {1, -1, 2};
    NDimensionalStepper nds = new NDimensionalStepper(limits, order, starts, steps);
    do {
      System.out.println(nds);
    } while (nds.step());
  }

  public static void main(String args[]) {
    new Test().test();
  }

  public static class NDimensionalStepper {
    // The current positions in each dimension.
    // Note that i[order[0]] is the fastest mover.
    final int[] i;
    // Starts.
    final int[] starts;
    // Steps.
    final int[] steps;
    // Limits.
    final int[] limits;
    // Order.
    final int[] order;
    // The (unordered) dimension we last stepped.
    int d = 0;

    // Full constructor.
    public NDimensionalStepper(int[] limits, int[] order, int[] starts, int[] steps) {
      // Should parameter check to ensure all are the same length.
      // Should also check that each dimension will terminate.
      this.i = Arrays.copyOf(starts, starts.length);
      this.starts = Arrays.copyOf(starts, starts.length);
      this.steps = Arrays.copyOf(steps, steps.length);
      this.limits = Arrays.copyOf(limits, limits.length);
      this.order = Arrays.copyOf(order, order.length);
    }

    // Default steps to 1.
    public NDimensionalStepper(int[] limits, int[] order, int[] starts) {
      this(limits, order, starts, defaultSteps(limits, starts));
    }

    // Default steps - 1 Towards limits.
    private static int[] defaultSteps(int[] limits, int[] starts) {
      int[] steps = new int[limits.length];
      for (int i = 0; i < limits.length; i++) {
        // Step towrds limits.
        steps[i] = (int) Math.signum(limits[i] - starts[i]);
      }
      return steps;
    }

    // Default starts to 0.
    public NDimensionalStepper(int[] limits, int[] order) {
      this(limits, order, defaultStarts(limits.length));
    }

    // Default starts - 0, 0, ...
    private static int[] defaultStarts(int d) {
      int[] starts = new int[d];
      Arrays.fill(starts, 0);
      return starts;
    }

    // Default order to normal.
    public NDimensionalStepper(int[] limits) {
      this(limits, defaultOrder(limits.length));
    }

    // Default order - ..., 1, 0
    private static int[] defaultOrder(int d) {
      int[] order = new int[d];
      for (int i = 0; i < d; i++) {
        order[i] = d - i - 1;
      }
      return order;
    }

    // Get the current position in dimension d.
    public int get(int d) {
      return i[d];
    }

    // Take just one step. Return false if cant.
    public boolean step() {
      boolean stepped = false;
      boolean finished = false;
      while (!stepped && !finished) {
        // Which dimension should be stepped (depends on order).
        int o = order[d];
        // Can we step in the current dimension?
        while (finished(o) && d < order.length - 1) {
          // Reached a limit! - Move up one dimension.
          o = order[++d];
        }
        if (d < order.length && !finished(o)) {
          // Step it.
          i[o] += steps[o];
          stepped = true;
          // Zero all lower dimensions.
          while (d > 0) {
            d -= 1;
            i[order[d]] = starts[order[d]];
          }
        } else {
          // Got to the last without finding one below limit. Finished!
          finished = true;
        }
      }
      return !finished;
    }

    // Equal or passed the limits.
    private boolean finished(int o) {
      int sign = (int) Math.signum(steps[o]);
      return sign * (i[o] + steps[o]) >= sign * limits[o];
    }

    @Override
    public String toString() {
      StringBuilder s = new StringBuilder();
      s.append("{");
      for (int d = 0; d < order.length; d++) {
        s.append(get(d));
        if (d < order.length - 1) {
          s.append(",");
        }
      }
      s.append("}");
      return s.toString();
    }
  }
}

我对您的三个场景的等效测试如下所示:

My tests of the equivalents of your three scenarios look like:

  private void testBuild1(Build build) {
    System.out.println("Build: x,y,z");
    for (int x = 0; x < build.getWidth(); x++) {
      for (int y = 0; y < build.getHeight(); y++) {
        for (int z = 0; z < build.getLength(); z++) {
          System.out.println("{" + x + "," + y + "," + z + "}");
        }
      }
    }
    int[] limits = {build.getWidth(), build.getHeight(), build.getLength()};
    testNDS(new NDimensionalStepper(limits));
  }

  private void testBuild2(Build build) {
     System.out.println("Build: z,y,x");
    for (int z = 0; z < build.getLength(); z++) {
      for (int y = 0; y < build.getHeight(); y++) {
        for (int x = 0; x < build.getWidth(); x++) {
          System.out.println("{" + x + "," + y + "," + z + "}");
        }
      }
    }
    int[] limits = {build.getWidth(), build.getHeight(), build.getLength()};
    int[] order = {0,1,2};
    testNDS(new NDimensionalStepper(limits, order));
  }

  private void testBuild3(Build build) {
    System.out.println("Build: x--,y,z");
    for (int x = build.getWidth(); x > 0; x--) {
      for (int y = 0; y < build.getHeight(); y++) {
        for (int z = 0; z < build.getLength(); z++) {
          System.out.println("{" + x + "," + y + "," + z + "}");
        }
      }
    }
    int[] limits = {0, build.getHeight(), build.getLength()};
    int[] order = {2,1,0};
    int[] starts = {build.getWidth(), 0, 0};
    int[] steps = {-1, 1, 1};
    testNDS(new NDimensionalStepper(limits, order, starts, steps));
  }

  private void testNDS(NDimensionalStepper nds) {
    System.out.println("--nds--");
    do {
      System.out.println(nds);
    } while (nds.step());
  }

这篇关于更改 for 循环的顺序?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆