改变for循环的顺序?

我有一种情况,我需要根据用户输入循环不同顺序的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 } } } 

如果不对每个案例进行硬编码,有没有办法做到这一点?

这是一个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()); } 

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

你可以像这样编码:

 //Code to populate XInit, XEnd, YInit, YEnd, ZInit, ZEnd based on user input for(int x = XInit; x < XEnd; x=XInit 

注意:您甚至可能希望在单独的方法中抽象出XInit,XEnd等参数的计算。

你的“东西”可能正在访问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甚至可以通过列出该类的可用选项来帮助您。 我认为你组织它的方式已经很好了。