2013-03-30 51 views
5

我有一种情况,我需要根据用户输入以不同顺序循环xyz坐标。所以我在3D空间中的一个区域,然后是一组for循环如此。更改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 
     } 
    } 
} 

有没有办法做到这一点,没有硬编码每个案件?

+7

使用迭代器代替。你的程序被硬编码为“iter1”,“iter2”,“iter3”,但在进入循环之前,根据用户输入设置它们。 – aioobe

+0

这可以工作。我只需要为xyz坐标系设置一些集合,并在需要时反向它们即可。 – Antonio

+0

@aioobe如果这是一个答案我会投票! –

回答

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

真棒它是完美的作品。谢谢 :) – Antonio

1

你说取决于用户输入循环变化的顺序。处理用户输入的逻辑必须写入。在一个单独的方法你甚至可以抽象xinit的计算,xend的等参数:

你可以像这样的代码:

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

注意。

+0

你能给出完整的答案吗?对于case1,case2和case3,XInit,XEnd,YInit,YEnd,ZInit,ZEnd具有哪些值? –

+0

我还没有指定,因为它取决于应用程序使用的逻辑。用户输入和迭代次序之间的关系不清楚。 – prashant

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甚至会通过列出该类可用的选项帮助你。我认为你组织它的方式已经很好了。