5

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

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

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

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

有没有办法做到这一点而无需对每个案例进行硬编码?

4

3 回答 3

1

您说根据用户输入循环更改的顺序。必须编写处理用户输入的逻辑。

你可以这样编码:

//Code to populate XInit, XEnd, YInit, YEnd, ZInit, ZEnd based on user input

    for(int x = XInit; x < XEnd; x=XInit<XEnd?x+1:x-1){
       for(int y = YInit; y < YEnd; y=YInit<YEnd?y+1:y-1){
         for(int z = ZInit; z < ZEnd; z=ZInit<ZEnd?z+1:z-1){
            //do stuff
           }
        }
     }

注意:您甚至可能希望将 XInit、XEnd 等参数的计算抽象到一个单独的方法中。

于 2013-03-30T22:44:35.463 回答
1

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

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

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

  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());
  }
于 2013-03-31T00:05:23.823 回答
0

您的“东西”可能会访问 x、y 和 z 的值,因此您进行硬编码的方式可能是最容易遵循的。您的方法名称可以清楚地表明顺序。对于您提供的三个示例,它看起来类似于:

public void somethingXYZ(Build build, Stuff stuff) {...}
public void somethingZYX(Build build, Stuff stuff) {...}
public void somethingXnYZ(Build build, Stuff stuff) {...}

当您正在编码并想要选择其中一种方法时,您的 IDE 甚至会通过列出该类的可用选项来帮助您。我认为你组织它的方式已经很好了。

于 2013-03-30T23:51:37.837 回答