Dentro de un ciclo for, ¿debería mover la condición de ruptura al campo de condición si es posible? [cerrado]

48

A veces necesito bucles que necesitan un descanso como este:

for(int i=0;i<array.length;i++){
    //some other code
    if(condition){
        break;
    }
}

Me siento incómodo escribiendo

if(condition){
    break;
}

porque consume 3 líneas de código. Y descubrí que el bucle se puede reescribir como:

                                   ↓
for(int i=0;i<array.length && !condition;i++){
    //some other code
}

Entonces mi pregunta es, ¿es una buena práctica mover la condición al campo de condición para reducir líneas de códigos si es posible?

ocomfd
fuente
77
Depende de lo que sea conditionen particular.
Bergi
44
Hay una razón por la cual misra prohíbe el uso de "romper" y "continuar" dentro de los bucles. Vea también esto: stackoverflow.com/q/3922599/476681
B 27овић
35
Creo que el número de líneas en sí no es el problema real. Podría escribirse en una línea. si (condición) se rompe; El problema en mi opinión es la legibilidad. Personalmente no me gusta romper un bucle que no sea usar la condición del bucle.
Joe
97
porque consume 3 líneas de código Una muy, muy, muy mala razón para que no le guste ningún estilo. Las "líneas de código de consumo" de la OMI se encuentran entre algo irrelevante y algo bueno. Intentar meter demasiada lógica en muy pocas líneas da como resultado un código ilegible y errores difíciles de encontrar.
Andrew Henle
3
Posiblemente opinión impopular: for(int i=0;i<array.length && !condition;i++)es relativamente poco común y puede ser pasado por alto por alguien que solo está leyendo el código; Este podría ser un buen caso de uso para un bucle whileo do while, que a menudo tiene múltiples condiciones de interrupción en la definición del bucle.
Jules

Respuestas:

154

Esos dos ejemplos que dio no son funcionalmente equivalentes. En el original, la prueba de condición se realiza después de la sección "algún otro código", mientras que en la versión modificada, se realiza primero, al comienzo del cuerpo del bucle.

El código nunca debe reescribirse con el único propósito de reducir el número de líneas. Obviamente, es un buen bono cuando funciona de esa manera, pero nunca debe hacerse a expensas de la legibilidad o corrección.

Pete
fuente
55
Entiendo su opinión, pero he mantenido suficiente código heredado donde el ciclo tiene varios cientos de líneas y hay múltiples saltos condicionales. Hace que la depuración sea muy difícil cuando esperas que el código llegue al salto condicional que esperas, pero el código anterior ejerció su salto condicional primero. ¿Cómo manejas ese código? En ejemplos breves como el anterior, es fácil olvidarse de ese tipo de escenario demasiado común.
Berin Loritsch
84
@BerinLoritsch: ¡La forma correcta de lidiar con eso es no tener bucles de cientos de líneas de largo!
Chris
27
@Walfrat: Si reescribir no es una opción, ya no hay una pregunta. Una vez dicho esto, generalmente puede usar de manera bastante segura un refactor de tipo "Método de extracción" para mover bloques de código, lo que debería acortar el bucle del método principal y, con suerte, hacer que la lógica fluya más obvia. Es realmente un caso por caso. Mantendré mi regla general de mantener los métodos cortos y definitivamente mantendré la lógica del bucle nexted corta, pero no quiero tratar de decir nada más que eso en un sentido general ...
Chris
44
La brevedad de @AndrewHenle es legibilidad, al menos en el sentido de que aumentar la verbosidad siempre reduce la legibilidad y la facilidad de mantenimiento. La reducción de LOC se logra aumentando la densidad y elevando el nivel de abstracción, y está muy estrechamente correlacionado con la capacidad de mantenimiento, como lo atestiguan otros pares de preguntas y respuestas en este mismo sitio.
Leushenko
55
@Joe una construcción Do-While es tan rara que es propenso a hacer que los desarrolladores que necesitan mantener ese código más adelante. ¡Algunos desarrolladores nunca los vieron! No estoy seguro de si un do-while mejoraría la legibilidad en absoluto; en todo caso, aumentaría la dificultad para comprender el código. Solo como ejemplo: mi base de código actual tiene alrededor de 15 años y tiene alrededor de 2 millones de LOC. Alrededor de cincuenta desarrolladores ya lo tocaron. Tiene exactamente cero bucles do-while!
T. Sar - Restablece a Monica
51

No compro el argumento de que "consume 3 líneas de código" y, por lo tanto, es malo. Después de todo, podrías escribirlo como:

if (condition) break;

y solo consume una línea.

Si ifaparece a la mitad del ciclo, por supuesto tiene que existir como una prueba separada. Sin embargo, si esta prueba aparece al final del bloque, ha creado un bucle que tiene una prueba continua en ambos extremos del bucle, posiblemente aumentando la complejidad del código. Sin embargo, tenga en cuenta que a veces la if (condition)prueba solo puede tener sentido después de que se haya ejecutado el bloque.

Pero suponiendo que ese no sea el caso, adoptando el otro enfoque:

for(int i=0;i<array.length && !condition;i++){
    //some other code
}

las condiciones de salida se mantienen juntas, lo que puede simplificar las cosas (especialmente si " algún otro código " es largo).

No hay una respuesta correcta aquí, por supuesto. Por lo tanto, tenga en cuenta las expresiones idiomáticas del idioma, cuáles son las convenciones de codificación de su equipo, etc. Pero, en general, adoptaría el enfoque de prueba única cuando tenga sentido funcional hacerlo.

David Arno
fuente
14
@ jpmc26, ¿mejor? No. ¿Estilo alternativo válido? Por supuesto.
David Arno
66
Es mejor, ya que es más difícil equivocarse cuando el código se edita más tarde, y no tiene desventajas notables.
jpmc26
44
Mantenerlos juntos debido a que "el contenido del bucle podría ser largo" parece ser un argumento débil. Cuando su contenido es difícil de leer, entonces tiene otros problemas además de guardar las dos líneas de código.
BlueWizard
12
@ jpmc26 No estoy de acuerdo. Los frenos son desorden superfluo en los condicionales más cortos y de una sola línea según esta respuesta. Sin es más elegante y más fácil a la vista. Son como un operador condicional ternario. Nunca olvidé agregar las llaves mientras las separaba en bloques de instrucciones más grandes; Ya estoy agregando nuevas líneas después de todo.
benxyzzy
3
Todo es una preferencia de estilo, pero si uno argumenta que es más seguro, no estaría de acuerdo con ese razonamiento. Yo mismo prefiero sin llaves y en la siguiente línea, pero eso no significa que sea más o menos válido que otros estilos
phflack
49

Este tipo de pregunta ha provocado un debate casi tan largo como la programación. Para lanzar mi sombrero al ring, iría por la versión con la breakcondición y he aquí por qué (para este caso específico ):

El forbucle está allí para especificar los valores de iteración en el bucle. Codificar la condición de ruptura dentro de eso solo enturbia la lógica de la OMI.

Tener un elemento separado breakdeja en claro que durante el procesamiento normal, los valores son los especificados en el forbucle y el procesamiento debe continuar, excepto donde entra la condición.

Como antecedentes, comencé a codificar a break, luego puse la condición en el forbucle durante años (bajo la dirección de un programador excepcional) y luego volví al breakestilo porque se sentía mucho más limpio (y era el estilo predominante en los diversos tomos de código que estaba consumiendo).

Es otra de esas guerras santas al final del día: algunos dicen que nunca debes salir de un ciclo artificialmente, de lo contrario no es un ciclo real. Haz lo que sientas que es legible (tanto para ti como para los demás). Si lo tuyo es reducir las pulsaciones de teclas, practica golf de código los fines de semana: cerveza opcional.

Robbie Dee
fuente
3
Si la condición tiene un buen nombre, como "encontrado" (por ejemplo, si está buscando algo en la matriz), es una buena idea ponerlo en la cabeza del bucle for.
user949300
1
Me dijeron que los forbucles se usan cuando se conoce el número de iteraciones (por ejemplo, cuando no hay una condición de interrupción pero el final de la matriz / lista) y whilecuando no. Este parece ser el caso de un whilebucle. Si la legibilidad es la preocupación, idx+=1es mucho más limpio leer dentro de un bucle que un if/elsebloque
Laiv
No puede simplemente poner la condición de interrupción en el bucle si hay un código que la sigue, por lo que al menos tendría que escribir "if (condición) {encontrado = verdadero; continuar;}
gnasher729
Estamos tan acostumbrados a los for(int i=0; i<something;i++)bucles que supongo que la mitad de los desarrolladores realmente no recuerdan que los forbucles se pueden usar de manera diferente y, por lo tanto, tienen dificultades para comprender la &&conditionparte.
Ralf Kleberhoff
@RalfKleberhoff De hecho. He visto a muchos nuevos desarrolladores expresar sorpresa de que las expresiones de declaración tripartitas sean todas opcionales. Ni siquiera recuerdo la última vez que vi for(;;)...
Robbie Dee
43

forlos bucles son para la iteración sobre algo 1 : no son solo lol-vamos a sacar algunas cosas al azar del cuerpo y ponerlas en el encabezado del bucle: las tres expresiones tienen muy significados específicos:

  • El primero es para inicializar el iterador . Puede ser un índice, un puntero, un objeto de iteración o lo que sea, siempre que se use para la iteración .
  • El segundo es para verificar si llegamos al final.
  • El tercero es para avanzar el iterador.

La idea es separar el manejo de la iteración ( cómo iterar) de la lógica dentro del bucle ( qué hacer en cada iteración). Muchos idiomas generalmente tienen un ciclo para cada uno que lo libera de los detalles de la iteración, pero incluso si su idioma no tiene esa construcción, o si no se puede usar en su escenario, aún debe limitar el encabezado del ciclo a la iteración de manejo.

Entonces, debe preguntarse: ¿es su condición sobre el manejo de la iteración o sobre la lógica dentro del bucle? Lo más probable es que se trata de la lógica dentro del bucle, por lo que debe verificarse dentro del bucle en lugar de en el encabezado.

1 A diferencia de otros bucles, que están "esperando" que algo suceda. Un for/ foreachloop debe tener el concepto de una "lista" de elementos para iterar, incluso si esa lista es perezosa o infinita o abstracta.

Idan Arye
fuente
55
Este fue mi primer pensamiento cuando leí la pregunta. Decepcionado, tuve que desplazarme por media docena de respuestas para ver a alguien decirlo
Nemo
44
Umm ... todos los bucles son para iteración, eso es lo que significa la palabra "iteración" :-). ¿Supongo que te refieres a algo como "iterar sobre una colección" o "iterar usando un iterador"?
Saludos del
3
@psmears OK, tal vez elegí la palabra incorrecta: el inglés no es mi lengua materna, y cuando pienso en iteración pienso en "iteración sobre algo". Arreglaré la respuesta.
Idan Arye
Un caso intermedio es donde la condición es algo así someFunction(array[i]). Ahora ambas partes de la condición son sobre lo que estás iterando, y tendría sentido combinarlas con &&el encabezado del bucle.
Barmar
Respeto tu posición, pero no estoy de acuerdo. Creo que los forbucles en el fondo son contadores, no bucles en una lista, y esto es compatible con la sintaxis de forlos idiomas anteriores (estos idiomas a menudo tenían una for i = 1 to 10 step 2sintaxis y el stepcomando, incluso permitiendo un valor inicial que no es el índice del primero elemento: insinúa un contexto numérico, no un contexto de lista). El único caso de uso que creo que admite forbucles, ya que solo iterar sobre una lista es paralelizar, y eso requiere una sintaxis explícita ahora de todos modos para no romper el código haciendo, por ejemplo, una ordenación.
Logan Pickup
8

Recomiendo usar la versión con if (condition). Es más legible y más fácil de depurar. Escribir 3 líneas adicionales de código no te romperá los dedos, pero facilitará que la siguiente persona entienda tu código.

Aleksander
fuente
1
Solo si (como se ha comentado) el bloque de bucle no tiene cientos de líneas de código y la lógica interna no es ciencia espacial. Creo que su argumento está bien, pero echo de menos algo como naming thingspara entender lo que está sucediendo y cuándo se cumple la condición de ruptura.
Laiv
2
@Laiv Si el bloque de bucle tiene cientos de líneas de código dentro, entonces hay problemas más grandes que la pregunta de dónde escribir la condición de interrupción.
Aleksander
Es por eso que sugerí contextualizar la respuesta, porque no siempre es cierto.
Laiv
8

Si está iterando sobre una colección donde se deben omitir ciertos elementos, le recomiendo una nueva opción:

  • Filtra tu colección antes de iterar

Tanto Java como C # hacen que esto sea relativamente trivial. No me sorprendería si C ++ tuviera una forma de hacer un iterador elegante para omitir ciertos elementos que no se aplican. Pero esta es realmente una opción si su idioma de elección lo admite, y la razón por la que está utilizando breakes porque hay condiciones sobre si procesa un elemento o no.

De lo contrario, hay una muy buena razón para que su condición forme parte del ciclo for, suponiendo que su evaluación inicial sea correcta.

  • Es más fácil ver cuándo un ciclo termina temprano

He trabajado en el código donde su bucle for toma unos cientos de líneas con varios condicionales y algunas matemáticas complejas que están sucediendo allí. Los problemas que encuentra con esto son:

  • break los comandos enterrados en la lógica son difíciles de encontrar y a veces sorprendentes
  • La depuración requiere recorrer cada iteración del ciclo para comprender realmente lo que está sucediendo
  • Gran parte del código no tiene refactorizaciones fácilmente reversibles disponibles o pruebas unitarias para ayudar con la equivalencia funcional después de una reescritura

En esa situación, recomiendo las siguientes pautas en orden de preferencia:

  • Filtre la colección para eliminar la necesidad de un breakposible
  • Haga la parte condicional de las condiciones del bucle for
  • Coloque los condicionales con el breaken la parte superior del bucle si es posible
  • Agregue un comentario de varias líneas que llame la atención sobre el descanso y por qué está allí

Estas pautas siempre están sujetas a la corrección de su código. Elija la opción que mejor represente la intención y mejore la claridad de su código.

Berin Loritsch
fuente
1
La mayor parte de esta respuesta está bien. Pero ... puedo ver cómo filtrar una colección podría eliminar la necesidad de continuedeclaraciones, pero no veo cómo ayudan mucho break.
user949300
1
@ user949300 Un takeWhilefiltro puede reemplazar breakdeclaraciones. Si tiene uno, Java, por ejemplo, solo los obtiene en Jave 9 (no es que sea tan difícil implementarlo usted mismo)
Idan Arye
1
Pero en Java aún puede filtrar antes de la iteración. Usando streams (1.8 o posterior) o usando Apache Collections (1.7 o anterior).
Laiv
@IdanArye: hay bibliotecas de complementos que agregan tales funciones a la API de secuencias de Java (por ejemplo, JOO-lambda )
Julio
@IdanArye nunca escuchó sobre una toma antes de tu comentario. Al vincular explícitamente el filtro a un orden me parece inusual y hacky, ya que en un filtro "normal" cada elemento devuelve verdadero o falso, independientemente de lo que viene antes o después. De esta manera puedes ejecutar cosas en paralelo.
user949300
8

Recomiendo encarecidamente adoptar el enfoque de menor sorpresa a menos que obtenga un beneficio significativo al hacer lo contrario.

Las personas no leen todas las letras cuando leen una palabra, y no leen todas las palabras cuando leen un libro; si son expertos en la lectura, miran los contornos de las palabras y oraciones y dejan que su cerebro complete el resto .

Entonces, es probable que el desarrollador ocasional suponga que esto es solo un estándar para el bucle y ni siquiera lo mire:

for(int i=0;i<array.length&&!condition;i++)

Si quiere usar ese estilo independientemente, le recomiendo cambiar las partes for(int i=0;i<y ;i++)que le digan al cerebro del lector que este es un estándar para el bucle.


Otra razón para ir con if- breakes que no siempre se puede utilizar el enfoque con el forinnecesaria cualquier condición. Usted tiene que utilizar if- breakcuando la condición de rotura es demasiado complejo para ocultar dentro de una fordeclaración, o se basa en variables que sólo se puede acceder en el interior del forbucle.

for(int i=0;i<array.length&&!((someWidth.X==17 && y < someWidth.x/2) || (y == someWidth.x/2 && someWidth.x == 18);i++)

Así que si usted decide ir con if- break, que está cubierto. Pero si usted decide ir con for-condiciones, usted tiene que utilizar una mezcla de if- breaky for-condiciones. Para ser coherente, que tendrá que mover las condiciones de ida y vuelta entre las for-condiciones y if- breakcada vez que cambian las condiciones.

Peter
fuente
4

Su transformación está asumiendo que todo lo que conditionse evalúa a truemedida que ingresa al bucle. No podemos comentar la corrección de eso en este caso porque no está definido.

Después de tener éxito en "reducir las líneas de código" aquí, puede continuar mirando

for(int i=0;i<array.length;i++){
    // some other code
    if(condition){
        break;
    }
    // further code
}

y aplicar la misma transformación, llegando a

for(int i=0;i<array.length && !condition;i++){
    // some other code
    // further code
}

Lo cual es una transformación no válida, como ahora haces incondicionalmente further codedonde antes no lo hacías.

Un esquema de transformación mucho más seguro es extraer some other codey evaluar conditionuna función separada

bool evaluate_condition(int i) // This is an horrible name, but I have no context to improve it
{
     // some other code
     return condition;
}

for(int i=0;i<array.length && !evaluate_condition(i);i++){
    // further code
}
Caleth
fuente
4

TL; DR Haz lo que se lea mejor en tu circunstancia particular

Tomemos este ejemplo:

for ( int i = 1; i < array.length; i++ ) 
{
    if(something) break;
    // perform operations
}

En este caso, no queremos que se ejecute ninguno de los códigos del bucle for si somethinges verdadero, por lo que somethinges razonable mover la prueba al campo de condición.

for ( int i = 1; i < array.length && !something; i++ )

Por otra parte, dependiendo de si somethingse puede establecer trueantes del ciclo, pero no dentro de él, esto podría ofrecer más claridad:

if(!something)
{
    for ( int i = 1; i < array.length; i++ )
    {...}
}

Ahora imagina esto:

for ( int i = 1; i < array.length; i++ ) 
{
    // perform operations
    if(something) break;
    // perform more operations
}

Estamos enviando un mensaje muy claro allí. Si somethingse cumple mientras se procesa la matriz, abandone toda la operación en este punto. Para mover el cheque al campo de condición que necesita hacer:

for ( int i = 1; i < array.length && !something; i++ ) 
{
    // perform operations
    if(!something)
    {
        // perform more operations
    }
}

Podría decirse que el "mensaje" se ha enlodado, y estamos verificando la condición de falla en dos lugares: ¿qué sucede si la condición de falla cambia y olvidamos uno de esos lugares?

Por supuesto, hay muchas más formas diferentes para un bucle y una condición, todas con sus propios matices.

Escriba el código para que se lea bien (esto es obviamente algo subjetivo) y de manera concisa. Fuera de un conjunto draconiano de pautas de codificación, todas las "reglas" tienen excepciones. Escriba lo que siente que expresa mejor la toma de decisiones y minimice las posibilidades de errores futuros.

Grimm The Opiner
fuente
2

Si bien puede ser atractivo porque ve todas las condiciones en el encabezado del bucle y breakpuede ser confuso dentro de bloques grandes, un forbucle es un patrón en el que la mayoría de los programadores esperan bucles en algún rango.

Especialmente porque lo hace, agregar una condición de descanso adicional puede causar confusión y es más difícil ver si es funcionalmente equivalente.

A menudo, una buena alternativa es usar un bucle whileo do {} whileque verifique ambas condiciones, suponiendo que su matriz tenga al menos un elemento.

int i=0
do {
    // some other code
    i++; 
} while(i < array.length && condition);

Al usar un bucle que solo verifica una condición y no ejecuta código desde el encabezado del bucle, deja muy claro cuándo se verifica la condición y cuál es la condición real y cuál es el código con efectos secundarios.

allo
fuente
A pesar de que esta pregunta ya tiene algunas buenas respuestas, quería votar específicamente esto porque tiene un punto importante: para mí, tener algo más que una simple comprobación de límite en el bucle for ( for(...; i <= n; ...)) hace que el código sea más difícil de leer porque tengo detenerse y pensar en lo que está sucediendo aquí y podría pasar por alto la condición en la primera pasada porque no espero que esté allí. Para mí, un forbucle implica que está recorriendo un rango, si hay una condición de salida especial, debe hacerse explícito con un if, o puede usar a while.
CompuChip
1

Esto es malo, ya que el código está destinado a ser leído por humanos: los forbucles no idiomáticos a menudo son confusos de leer, lo que significa que es más probable que los errores se escondan aquí, pero el código original pudo haber sido posible mientras se mantenía ambos Corto y legible.

Si lo que desea es encontrar un valor en una matriz (el ejemplo de código proporcionado es algo genérico, pero también puede ser este patrón), puede intentar explícitamente utilizar una función proporcionada por un lenguaje de programación específicamente para ese propósito. Por ejemplo (pseudocódigo, como no se especificó un lenguaje de programación, las soluciones varían según un lenguaje en particular).

array.find(item -> item.valid)

Esto debería acortar notablemente la solución y simplificarla, ya que su código dice específicamente lo que necesita.

Konrad Borowski
fuente
1

Pocas razones en mi opinión que dice, no deberías.

  1. Esto reduce la legibilidad.
  2. La salida puede no ser la misma. Sin embargo, se puede hacer con un do...whilebucle (no while) ya que la condición se verifica después de una ejecución de código.

Pero además de eso, considera esto,

for(int i=0;i<array.length;i++){

    // Some other code
    if(condition1){
        break;
    }

    // Some more code
    if(condition1){
        break;
    }

    // Some even more code
}

Ahora, ¿realmente puedes lograrlo agregando estas condiciones a esa forcondición?

Duro
fuente
¿Qué es la " apertura "? ¿Quieres decir " opinión "?
Peter Mortensen
¿Qué quieres decir con "Pocas razones en la apertura que dice, no deberías" ? ¿Puedes elaborar?
Peter Mortensen
0

Creo que eliminarlo breakpuede ser una buena idea, pero no para guardar líneas de código.

La ventaja de escribir sin él breakes que la condición posterior del bucle es obvia y explícita. Cuando finaliza el ciclo y ejecuta la siguiente línea del programa, su condición de ciclo i < array.length && !conditiondebe haber sido falsa. Por lo tanto, iera mayor o igual que la longitud de su matriz, o conditiones cierto.

En la versión con break, hay una trampa oculta. La condición del bucle dice que el bucle termina cuando ha ejecutado algún otro código para cada índice de matriz válido, pero de hecho hay una breakdeclaración que podría terminar el bucle antes de eso, y no lo verá a menos que revise el código del bucle. muy cuidadosamente. Y los analizadores estáticos automáticos, incluida la optimización de compiladores, también podrían tener problemas para deducir cuáles son las condiciones posteriores del bucle.

Esta fue la razón original por la que Edgar Dijkstra escribió "Goto Considerado Dañino". No fue una cuestión de estilo: romper un círculo hace que sea difícil razonar formalmente sobre el estado del programa. He escrito muchas break;declaraciones en mi vida, y una vez como adulto, incluso escribí un goto(para salir de múltiples niveles de un ciclo interno crítico para el rendimiento y luego continuar con otra rama del árbol de búsqueda). Sin embargo, es mucho más probable que escriba una returndeclaración condicional desde un bucle (que nunca ejecuta el código después del bucle y, por lo tanto, no puede acumular sus condiciones posteriores) que a break.

Posdata

De hecho, refactorizar el código para dar el mismo comportamiento podría necesitar más líneas de código. Su refactorización podría ser válida para algún otro código en particular o si podemos demostrar que conditioncomenzará en falso. Pero su ejemplo es equivalente en el caso general a:

if ( array.length > 0 ) {
  // Some other code.
}
for ( int i = 1; i < array.length && !condition; i++ ) {
  // Some other code.
}

Si algún otro código no es de una sola línea, puede moverlo a una función para que no se repita, y casi ha refactorizado su bucle en una función recursiva de cola.

Sin embargo, reconozco que este no era el punto principal de su pregunta, y lo mantenía simple.

Davislor
fuente
El problema no es que la ruptura hace que sea difícil discutir sobre el código, sino que la ruptura en lugares aleatorios hace que el código sea complicado. Si eso es realmente necesario, entonces no es difícil discutir debido a la ruptura, sino porque el código debe hacer cosas complicadas.
gnasher729
He aquí por qué no estoy de acuerdo: si sabes que no hay una breakdeclaración, entonces sabes cuál es la condición del bucle y que el bucle se detiene cuando esa condición es falsa. Si hay un break? Luego, hay varias formas en que el ciclo podría terminar, y en el caso general, descubrir cuándo una de ellas podría detener el ciclo es, literalmente, resolver el problema de detención. En la práctica, mi mayor preocupación es que el bucle parece que hace una cosa, pero en realidad, quien escribió el código después del bucle pasó por alto un caso marginal oculto en su lógica compleja. Las cosas en la condición de bucle son difíciles de perder.
Davislor
0

Sí, pero su sintaxis no es convencional y, por lo tanto, es mala (tm)

Esperemos que tu idioma sea compatible con algo como

while(condition) //condition being a condition which if true you want to continue looping
{
    do thing; //your conditionally executed code goes here
    i++; //you can use a counter if you want to reference array items in order of index
}
Ewan
fuente
2
tal vez debería haber usado una palabra diferente para 'condición'. No quise decir literalmente que significara exactamente la misma condición en el ejemplo
Ewan
1
El bucle for no solo no es ni remotamente poco convencional, no hay absolutamente ninguna razón para que un bucle while de esta forma sea mejor que un bucle equivalente. De hecho, la mayoría de la gente diría que es peor, como los autores de las Pautas Básicas de CPP
Sean Burton
2
Algunas personas simplemente odian las alternativas creativas. O mirando un problema de una manera diferente a la que se les ocurrió. O más generalmente, asnos inteligentes. ¡Siento tu dolor hermano!
Martin Maat
1
@sean lo siento amigo, sé que la gente odia que les digan que están equivocados, pero lo remito a es.77
Ewan
2
Esto whileenfatiza el monstruo en el código, la excepción oculta en el código de rutina / mundano. La lógica de negocios es frontal y central, la mecánica de bucle está subsumida. Evita la reacción de "espera un minuto ..." a la foralternativa del bucle. Esta respuesta soluciona el problema. Absolutamente voto.
radarbob
0

Si le preocupa que una fordeclaración demasiado compleja sea ​​difícil de leer, definitivamente es una preocupación válida. El desperdicio de espacio vertical también es un problema (aunque menos crítico).

(Personalmente, no me gusta la regla de que las ifdeclaraciones siempre deben tener llaves, que es en gran parte la causa del desperdicio de espacio vertical aquí. Tenga en cuenta que el problema es desperdiciar espacio vertical. Usar espacio vertical con líneas significativas no debería ser un problema).

Una opción es dividirlo en varias líneas. Esto es definitivamente lo que debe hacer si está usando fordeclaraciones realmente complejas , con múltiples variables y condiciones. (Esto es para mí un mejor uso del espacio vertical, dando tantas líneas como sea posible algo significativo).

for (
   int i = 0, j = 0;
   i < array.length && !condition;
   i++, j++
) {
   // stuff
}

Un mejor enfoque podría ser tratar de usar una forma más declarativa y menos imperativa. Esto variará según el idioma, o puede que necesite escribir sus propias funciones para habilitar este tipo de cosas. También depende de lo que conditionrealmente es. Presumiblemente, debe poder cambiar de alguna manera, dependiendo de lo que esté en la matriz.

array
.takeWhile(condition)  // condition can be item => bool or (item, index) => bool
.forEach(doSomething); // doSomething can be item => void or (item, index) => void
Dave Cousineau
fuente
Dividir una fordeclaración compleja o inusual en varias líneas es la mejor idea en toda esta discusión
usuario949300
0

Una cosa que se olvidó: cuando rompo un bucle (no hago todas las iteraciones posibles, sin importar cómo se implemente), generalmente es el caso de que no solo quiero salir del bucle, también querré saber por qué sucedió esto . Por ejemplo, si busco un elemento X, no solo rompo el ciclo, también quiero saber si se encontró X y dónde está.

En esa situación, tener una condición fuera del circuito es bastante natural. Entonces empiezo con

bool found = false;
size_t foundIndex;

y en el bucle escribiré

if (condition) {
    found = true;
    foundIndex = i;
    break;
}

con el bucle for

for (i = 0; i < something && ! found; ++i)

Ahora comprobar la condición en el bucle es bastante natural. Si hay una declaración de "interrupción" depende de si hay más procesamiento en el ciclo que desea evitar. Si se necesita algún procesamiento y otro no, es posible que tenga algo como

if (! found) { ... }

en algún lugar de tu circuito.

gnasher729
fuente