2011-06-01 20 views
14

¿Cuál es la mejor manera de finalizar todos los bucles anidados en el siguiente ejemplo? Una vez que la declaración if es verdadera, quiero terminar la declaración externa para (con I). En otras palabras, necesito que todo el ciclo se detenga. ¿Hay una mejor manera que establecer I a 10?¿Cómo finalizar el ciclo externo en los bucles anidados?

for (int I = 0; I < 10; I++) 
{ 
    for (int A = 0; A < 10; A++) 
    { 
     for (int B = 0; B < 10; B++) 
     { 
      if (something) 
       break; 
     } 
    } 
} 
+1

tenga en cuenta que su "arreglo" actual aún continúa el ciclo medio, lo que puede implicar más iteraciones del ciclo interno. Necesitarías 'I = A = 10;' –

+0

agregar un bool y verificarlo? – Foresp

+1

¿Cómo puede no ser un duplicado? – ripper234

Respuesta

32

me habría refactorizar a un método, y simplemente llamar return siempre que necesito.

También es posible usar goto, y yo tener utiliza goto para esto, pero se pone mal visto. Que es tonto; este escenario es por qué existe en el idioma.

void DoSomeStuff() 
{ 
    for (int I = 0; I < 10; I++) 
    { 
     for (int A = 0; A < 10; A++) 
     { 
      for (int B = 0; B < 10; B++) 
      { 
       if (something) 
        return; 
      } 
     } 
    } 
} 
...somewhere else... 
DoSomeStuff(); 
+0

@Marc Gravell: ¡Gracias Mark! Este código es en realidad parte de un método más grande, así que no puedo devolverlo. ¡Pero el goto es una gran idea! – Mirial

+7

@Mirial: seleccione el bloque que desea; en VS, "extraer método": esto es lo que quiero decir con refactor. AHORA tienes un método del que puedes 'regresar'. Básicamente, * puedes * refactorizar tu código para hacer esto, y probablemente deberías (parece que tu método es demasiado extenso). –

+1

Creo que si esta palabra clave no existiera en C#, entonces el desarrollador joven lo pensaría dos veces antes de implementar algo y crearlo adecuadamente. En mi humilde opinión, la instrucción goto solo debe ser utilizada por el compilador. –

1

Siempre se puede cumplir con los bucles expectativas:

si (algo) B = 10

Editar: (Aparece incluyó esto en su entrada a traves de una edición)

Si no le gusta cómo se ve, puede ajustar una función como:

Satisfacer (B, 10)

Luego se ve más limpio, pero realmente no es necesario.

3

Por qué no hacer:

for (int I = 0; I < 10 || !something; I++) 
     { 
      for (int A = 0; A < 10 || !something; A++) 
      { 
       for (int B = 0; B < 10; B++) 
       { 
        if (something) 
        { 
         I=10; 
         break; 
        } 
       } 
      } 
     } 
+1

Creo que te refieres a '&&! Something' en lugar de' || algo'. Además, algo muy bien puede ser un método, que desea ejecutar tan rara vez como sea posible. –

+0

porque no saldrías por completo. Volvería a caer en el A-loop y, por lo tanto, tal vez vuelva a insertarlo en el B-loop. Y tu ejemplo es simplemente mostrar que esta no es una buena idea porque es difícil de leer y mantener. – Oliver

+0

@Oliver: Totalmente de acuerdo, esto sería muy difícil de mantener y es bastante feo. Refactorizar a un método es la mejor manera de hacerlo, en mi humilde opinión, como Marc sugirió anteriormente. – Yuck

2

me inclinaría a favor de goto también otra cosa que va a tener que salir de cada bucle:

for (int I = 0; I < 10; I++) 
    { 
     for (int A = 0; A < 10; A++) 
     { 
      for (int B = 0; B < 10; B++) 
      { 
       if (something) 
        break; 
      } 
      if (something) 
       break; 
     } 
     if (something) 
      break; 
    } 
14

Suponiendo que desea salir de todo bucles, puede refactorizarlo en algo un poco más estructurado:

bool done = false; 
for (int i = 0; i < 10 && !done; i++) { 
    for (int a = 0; a < 10 && !done; a++) { 
     for (int b = 0; b < 10 && !done; b++) { 
      if (something) { 
       done = true; 
       continue; 
      } 
     } 
    } 
} 
1

la otra posibilidad es conectar el cheque en isSomething para todos los bucles. se agrega el

if (something)       
    break; 

en los 3 bucles

2

Si esta es la tarea final en el método, entonces puede regresar cuando la condición es verdadera. lo contrario tendrá que hacer todos los valores de max y valores

if (something)    
    { 
     I=10; 
     B=10; 
     A=10; 
     break; 
    } 
3

Siempre se puede explotar el hecho de que hay una sentencia condicional en el for así:

bool working = true; 
for (int i=0; i<10 && working; i++) 
{ 
    for (int j=0; j<10 && working; j++) 
    { 
     for (int k=0; k<10 && working; k++) 
     { 
      Console.WriteLine(String.Format("i={0}, j={1}, k={2}", i,j,k)); 
      if (i==5 && j==5 && k==5) 
      { 
       working = false; 
      } 
     } 
    } 
} 
+0

esto es en realidad una muy buena solución – nawfal

1

Personalmente me gustaría ir con el método de Paxdiablo arriba (+1 para eso), pero una alternativa está debajo - depende si el OP necesita saber cuáles son los números I, A y B cuando "algo" es verdadero, ya que iab fue declarado en el bucle, estoy adivinando no.

bool done = false; 
int i, a, b; 
for (i = 0; i < 10 ; i++) { 
    for (a = 0; a < 10 ; a++) { 
     for (b = 0; b < 10 ; b++) { 
      if (something) { 
       done = true; 
       break; 
      } 
     } 
     if (done) break; 
    } 
    if (done) break; 
} 
// i, a and B are set to the last numbers where "something" was true 
2
for (int I = 0; I < 10; I++) {  
    for (int A = 0; A < 10; A++)  {   
     for (int B = 0; B < 10; B++)   {    
      if (something){     
        B=13; 
        A=13; 
        I=13; 
      } 
      }  
    } 
} 

Una solución muy primitiva.

10

Si los cuerpos de bucle no producen un efecto secundario sino que simplemente buscan el primer valor donde "algo" es verdadero, entonces se solucionaría el problema eliminando todos los bucles en primer lugar.

var query = from I in Enumerable.Range(0, 10) 
      from A in Enumerable.Range(0, 10) 
      from B in Enumerable.Range(0, 10) 
      where something(I, A, B) 
      select new { I, A, B }; 
var result = query.FirstOrDefault(); 
if (result == null) 
{ 
    Console.WriteLine("no result"); 
} 
else 
{ 
    Console.WriteLine("The first result matching the predicate was {0} {1} {2}, 
     result.I, result.A, result.B); 
} 

Pero no haga esto si los bucles tienen efectos secundarios; las consultas son realmente un mal lugar para poner efectos secundarios. Si el bucle interno tiene un efecto secundario, entonces puede hacer algo como esto:

var triples = from I in Enumerable.Range(0, 10) 
       from A in Enumerable.Range(0, 10) 
       from B in Enumerable.Range(0, 10) 
       select new { I, A, B }; 
foreach(var triple in triples) 
{ 
    if (something(triple.I, triple.A, triple.B)) 
     break; 
    DoSomeSideEffect(triple.I, triple.A, triple.B); 
} 

y ahora hay un solo bucle de romper, no tres.

15

no me disparen, pero esto en realidad podría justificar una Goto:

for (int I = 0; I < 10; I++) { 
     for (int A = 0; A < 10; A++) { 
      for (int B = 0; B < 10; B++) { 
       if (something) 
        goto endOfTheLine; 
      } 
     } 
    } 
    endOfTheLine: 
    Console.WriteLine("Pure evilness executed"); 
+4

Este es en realidad un uso legítimo de 'goto' IMO. – Nobody

+5

Esta es exactamente la situación donde un goto es la mejor solución. No incurre en la sobrecarga de tiempo de ejecución de las comprobaciones de condición redundantes y es más directo y más fácil de entender que todas las alternativas publicadas hasta el momento. La peor desventaja de goto hoy en día es su mala reputación. – x4u

+1

¡Me niego a escuchar! ¡Disparale! – VitalyB

2

solución simple es refactorizar los bucles anidados en un método separado con el tipo de retorno ser relevante lo que quería saber en ese punto:

en mi caso supondré que quería los valores de I, A y B en ese punto, triviales con una Tuple en su lugar.

// original method 
... 
var x = FindFirst() 
... 

// separate method 
public Tuple<int,int,int> FindFirst() 
{ 
    for (int I = 0; I < 10; I++) 
    { 
     for (int A = 0; A < 10; A++) 
     { 
      for (int B = 0; B < 10; B++) 
      { 
       if (something) 
        return Tuple.Create(I,A,B); 
      } 
     }  
    } 
    return null; 
} 

Si necesita pasar ningún estado adicional al método (por los límites, o el algo bits) simplemente pasarlos como parámetros.

Si querían manejar de no poder encontrar el primero de una manera diferente, entonces algo así como

bool TryFindFirst(out Tuple<int,int,int> x) 

sería una alternativa.

Como nota al margen usando letras mayúsculas para los nombres de variables (especialmente individuales Ones letras) se considera un estilo pobre en C# (y muchos otros idiomas)

2

No sé si C# lo apoya, pero el apoyo algunos idiomas:

break n; 

Dónde n es el número de bucles anidados para romper.

Cuestiones relacionadas