2013-03-30 11 views
5

Ho una situazione in cui ho bisogno di ripetere le coordinate xyz in diversi ordini a seconda dell'input dell'utente. Quindi ho un'area nello spazio 3D, quindi un set di loop in questo modo.Cambia l'ordine di per loop?

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

ma a seconda dell'input dell'utente, l'ordine potrebbe essere come questo.

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

o addirittura negativo.

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'è un modo per farlo senza hard coding in ogni caso?

+7

Utilizzare invece iteratori. Il tuo programma è hardcoded per iterare su di loro come 'iter1',' iter2', 'iter3', ma prima di entrare nei loop, impostali secondo l'input dell'utente. – aioobe

+0

Potrebbe funzionare. Avrei solo bisogno di impostare alcune collezioni per le stringhe xyz e invertirle se ho bisogno di andare nella direzione opposta. – Antonio

+0

@aioobe se questa fosse una risposta avrei votato! –

risposta

1

Ecco uno stepper n-dimensionale in grado di eseguire qualsiasi numero di dimensioni in qualsiasi ordine da qualsiasi posizione iniziale a qualsiasi limite. Vedi il codice di prova per un esempio.

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

miei test degli equivalenti dei tre scenari assomigliano:

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

Impressionante funziona perfettamente. Grazie :) – Antonio

1

Hai detto che in base all'input dell'utente l'ordine delle modifiche del ciclo. La logica per la gestione dell'input dell'utente dovrà essere scritta.

È possibile codice come questo:

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

Nota: Si potrebbe anche voler di astrarre il calcolo di xinit, xend ecc parametri in un metodo separato.

+0

Puoi fornire una risposta completa? Quali valori dovrebbero 'XInit, XEnd, YInit, YEnd, ZInit, ZEnd' hanno per case1, case2 e case3? –

+0

Non l'ho specificato perché dipende dalla logica utilizzata dall'applicazione. La relazione tra input dell'utente e ordine di iterazione non è chiara dalla domanda. – prashant

0

È probabile che la tua "roba" acceda ai valori di x, yez, quindi il modo in cui stai codificando è probabilmente il più facile da seguire. I nomi dei metodi potrebbero indicare chiaramente l'ordine. Per i tre esempi hai dato, sarebbe simile a:

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

Quando si codifica e si desidera selezionare uno di questi metodi, il vostro IDE sarà anche aiutare elencando le opzioni disponibili per quella classe. Penso che il modo in cui lo stai organizzando funzionerebbe già bene.