2013-03-30 25 views
5

Mam sytuację, w której muszę pętli choć współrzędne xyz w różnych zamówieniach w zależności od danych wejściowych użytkownika. Więc ja obszar w przestrzeni 3D, a następnie zestaw pętli for jak to.Zmiana kolejności dla pętli?

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

ale w zależności od danych wprowadzanych przez użytkownika kolejność może być następująca.

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

lub nawet ujemny.

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

Czy jest jakiś sposób, aby to zrobić bez twardego kodowania w każdym przypadku?

+7

użytkowania iteratorów zamiast. Twój program jest na stałe zakodowany, aby go przetworzyć jako "iter1',' iter2', 'iter3', ale przed wejściem do pętli, ustaw je zgodnie z wprowadzonymi przez użytkownika danymi. – aioobe

+0

To może zadziałać. Musiałbym po prostu ustawić niektóre kolekcje na współrzędne xyz i odwrócić je, jeśli potrzebuję w przeciwnym kierunku. – Antonio

+0

@ aioobe, jeśli to była odpowiedź, chciałbym ją głosować! –

Odpowiedz

1

Oto n-wymiarowy stepper, który może wkroczyć w dowolną liczbę wymiarów w dowolnej kolejności, od dowolnych lokalizacji początkowych do dowolnych ograniczeń. Zobacz przykładowy kod testu.

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

Moje testy odpowiedników swoich trzech scenariuszy wyglądać następująco:

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

Świetne, działa idealnie. Dzięki :) – Antonio

1

Powiedziałeś w zależności od wprowadzonej przez użytkownika kolejności zmian w pętli. Logika do obsługi wprowadzania danych przez użytkownika będzie musiała zostać napisana.

można kodować tak:

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

Uwaga: Można nawet chcą abstrakcyjne obliczenia xinit, xKoniec itp parametry w osobnej metody.

+0

Czy możesz udzielić kompletnej odpowiedzi? Jakie wartości powinny mieć "XInit, XEnd, YInit, YEnd, ZInit, ZEnd' dla przypadku 1, przypadku2 i przypadku3? –

+0

Nie określono tego, ponieważ zależy to od logiki używanej przez aplikację. Relacja między wprowadzeniem użytkownika a kolejnością iteracji nie wynika z pytania. – prashant

0

Twoje "rzeczy" prawdopodobnie uzyskują dostęp do wartości x, yi z, więc najprawdopodobniej najłatwiejsze jest sposób, w jaki ciężko kodujesz. Twoje nazwy metod mogą jasno wskazywać kolejność. Przez trzy przykłady dałeś, to będzie wyglądać podobnie do:

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

Podczas kodowania i chcesz wybrać jedną z tych metod, IDE będzie jeszcze pomóc, wymieniając dostępne opcje dla tej klasy. Myślę, że sposób, w jaki to organizujesz, będzie już działał dobrze.

Powiązane problemy