2013-03-30 32 views
5

Tôi có một tình huống mà tôi cần phải lặp lại mặc dù tọa độ xyz theo các thứ tự khác nhau tùy thuộc vào đầu vào của người dùng. Vì vậy, tôi là một khu vực trong không gian 3D sau đó một tập hợp các vòng như vậy.Thay đổi thứ tự của các vòng lặp?

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

nhưng tùy thuộc vào đầu vào của người dùng, thứ tự có thể như thế này.

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

hoặc thậm chí là âm.

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

Có cách nào để thực hiện việc này mà không cần mã hóa cứng mọi trường hợp không?

+7

Sử dụng vòng lặp để thay thế. Chương trình của bạn được mã hóa cứng để lặp qua chúng như 'iter1',' iter2', 'iter3', nhưng trước khi nhập các vòng lặp, hãy thiết lập chúng theo đầu vào của người dùng. – aioobe

+0

Điều đó có thể hoạt động. Tôi chỉ cần thiết lập một số bộ sưu tập cho các coords xyz và đảo ngược chúng nếu tôi cần theo hướng ngược lại. – Antonio

+0

@aioobe nếu đây là câu trả lời tôi sẽ bỏ phiếu bầu chọn này! –

Trả lời

1

Dưới đây là một bước nhảy n-chiều có thể bước vào bất kỳ số thứ nguyên nào theo thứ tự bất kỳ từ bất kỳ vị trí bắt đầu nào đến bất kỳ giới hạn nào. Xem mã thử nghiệm để biết ví dụ.

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

xét nghiệm của tôi về sự tương đương của ba kịch bản của bạn trông giống như:

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

Tuyệt vời nó hoạt động hoàn hảo. Cảm ơn :) – Antonio

1

Bạn nói tùy thuộc vào đầu vào của người dùng thứ tự thay đổi vòng lặp. Logic để xử lý đầu vào của người dùng sẽ phải được viết.

Bạn có thể mã hóa như thế này:

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

Lưu ý: Bạn thậm chí có thể muốn để tóm tắt các tính xinit, XEnd, vv tham số trong một phương pháp riêng biệt.

+0

Bạn có thể trả lời đầy đủ không? Giá trị nào nên 'XInit, XEnd, YInit, YEnd, ZInit, ZEnd' có cho case1, case2 và case3? –

+0

Tôi chưa chỉ định điều đó vì nó phụ thuộc vào logic được ứng dụng sử dụng. Mối quan hệ giữa đầu vào của người dùng và thứ tự lặp lại không rõ ràng từ câu hỏi. – prashant

0

"Nội dung" của bạn có khả năng truy cập vào các giá trị của x, y và z, vì vậy cách bạn mã hóa cứng có lẽ là cách dễ nhất để thực hiện. Tên phương thức của bạn có thể cho biết rõ ràng thứ tự. Đối với ba ví dụ bạn đưa ra, nó sẽ trông tương tự như:

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

Khi bạn mã hóa và muốn chọn một trong các phương pháp đó, IDE của bạn thậm chí sẽ giúp bạn bằng cách liệt kê các tùy chọn có sẵn cho lớp đó. Tôi nghĩ cách bạn tổ chức nó sẽ hoạt động tốt.

Các vấn đề liên quan