2011-02-14 15 views
6

Teniendo en cuenta el código:¿Es una buena práctica para modificar la variable de índice dentro de un bucle FOR?

for (int i = 1; i <= 5; i++) 
     { 
      // Do work 
     } 

IS es siempre aceptable para cambiar el valor de i desde dentro del bucle? Por ejemplo:

for (int i = 1; i <= 5; i++) 
     { 
      if(i == 2) 
      { 
       i = 4; 
      } 
      // Do work 
     } 
+7

A menos que pueda presentar un buen caso de uso, no, ¿cómo podría hacerlo? Si tiene un buen caso de uso, hablaremos;) – delnan

+0

Generalmente se considera una mala práctica.Pero a veces ... –

+0

No creo que sea siempre "bueno", pero a veces, "bueno" no es una prioridad. –

Respuesta

9

En mi opinión, es demasiado confuso. Es mejor usar un lazo while en tal caso.

+7

De acuerdo, se trata de intención. La intención de un bucle for es su declaración, comienza en 0, termina en 42 e incrementa en 2. No espera que haga algo completamente diferente en el medio de su existencia. – rene

+0

No sé si hay alguna respuesta "correcta" estricta a esta pregunta. Algunos pueden argumentar que es una cuestión de estilo. Pero estoy de acuerdo en que agrega confusión. – DaveB

1

Yo diría que sí, pero solo en casos específicos.

Puede ser un poco confuso: si configuro i=4 ¿se incrementará o no antes de la siguiente iteración?

Puede ser un signo de olor a código: ¿quizás debería hacer una consulta LINQ antes y solo procesar elementos relevantes?

Usar con cuidado!

+0

Esta pregunta surgió cuando mantenía algún código heredado. En mi caso, LINQ no es una opción. - Buenos puntos – DaveB

4

Es aceptable, sin embargo, personalmente creo que esto debe evitarse. Como está creando un código que será inesperado para la mayoría de los desarrolladores, creo que está causando algo mucho menos sostenible.

En lo personal, si es necesario hacer esto, yo recomendaría cambiar a un bucle while:

int i=1; 
while (i <= 5) 
{ 
    if (i == 2) 
     i = 4; 

    ++i; 
} 

Esto, al menos, advierte a la gente que está utilizando la lógica no estándar.

Alternativamente, si usted está tratando de saltar elementos, utilice continue:

for (int i = 1; i <= 5; i++) 
{ 
    if (i == 2 || i == 3) 
     continue; 
} 

Si bien esto es, técnicamente, un poco más de las operaciones que sólo la creación de i directamente, se tendrá más sentido a otros desarrolladores ...

+0

Estoy de acuerdo. Evito esto en mi código porque creo que dificulta la lectura. Cuando veo un ciclo for, espero que el código dentro de él se ejecute una vez para cada iteración del ciclo. – DaveB

1

Sí, puede ser. Como hay una cantidad enorme de situaciones posibles, seguramente encontrará una excepción en la que se consideraría una buena práctica.

Pero parando el lado teórico de las cosas, diría: no. No lo hagas
Se vuelve bastante complicado y difícil de leer y/o seguir. Prefiero ver algo como la declaración continue, aunque tampoco soy un gran admirador de eso.

+0

+1 Me parece que se aleja del propósito del ciclo for porque, por naturaleza, el código dentro de él se debe ejecutar un número determinado de veces. – DaveB

1

Ves que con frecuencia en aplicaciones que analizar los datos. Por ejemplo, supongamos que estoy escaneando un archivo binario, y básicamente estoy buscando ciertas estructuras de datos. Yo podría tener código que hace lo siguiente:

int SizeOfInterestingSpot = 4; 
int InterestingSpotCount = 0; 
for (int currentSpot = 0; currentSpot < endOfFile; currentSpot++) 
{ 
    if (IsInterestingPart(file[currentSpot]) 
    { 
     InterestingSpotCount++; 
     //I know that I have one of what I need ,and further, that this structure in the file takes 20 bytes, so... 
     currentSpot += SizeOfInterestingSpot-1; //Skip the rest of that structure. 

    } 
} 
+1

Personalmente, encontraría esto más entendible como un ciclo while. –

+1

bien puede ser; pero no creo que sea incorrecto o incorrecto como un bucle FOR. – GWLlosa

+0

Tal como está escrito, esto dará como resultado un error de uno por uno (después de omitir el "punto de interés", comenzará la próxima iteración una ranura demasiado). Irónicamente, has ilustrado por qué usar 'for' de esta manera es peligroso. – zinglon

0

Citando Petar Minchev:

En mi opinión, es demasiado confuso. Es mejor usar un ciclo while en tal caso.

Y yo diría que al hacer eso, debe ser consciente de algunas cosas que podrían suceder, tales como bucles infinitos, bucles-prematuros cancelado, valores de variables extrañas o las matemáticas cuando se basan en el índice, y sobre todo (sin excluir ninguno de los otros) problemas de flujo de ejecución basados ​​en su índice y otras variables modificadas por el ciclo de falla.

Pero si tienes un caso así, ve por ello.

3

Un ejemplo sería la eliminación de elementos que coinciden con algunos criterios:

for (int i = 0; i < array.size(); /*nothing*/) 
{ 
    if (pred(array[i])) 
     i++; 
    else 
     array.erase(array.begin() + i); 
} 

Sin embargo una mejor idea sería utilizando iteradores:

for (auto it = array.begin(); it != array.end(); /*nothing*/) 
{ 
    if (pred(*it)) 
     ++it; 
    else 
     it = array.erase(it); 
} 

EDIT
Oh, lo siento, mi el código es C++, y la pregunta es sobre C#. Pero, sin embargo, la idea es la misma:

for (int i = 0; i < list.Length; /*nothing*/) 
{ 
    if (pred(list[i])) 
     i++; 
    else 
     list.RemoveAt(i); 
} 

y una mejor idea podría ser, por supuesto, simplemente

list.RemoveAll(x => !pred(x)); 

O en un estilo un poco más moderno,

list = list.Where(pred); 

(aquí list debe ser IEnumerable<...>)

1

Un ejemplo podría ser un for bucle donde desee en una determinada condición para repetir la iteración actual o volver a una iteración anterior o incluso omitir una cierta cantidad de iteraciones (en lugar de un continue numerado).

Pero estos casos son raros. E incluso para estos casos, considere que el bucle for es solo uno de los medios entre while, do y otras herramientas que se pueden usar. así que considera esto como una mala práctica y trata de evitarlo. su código también será menos legible de esa manera.

lo tanto, para concluir: Es posible (no en un foreach) es , pero se esfuerzan por evitar esto usandowhile y do etc. lugar.

1

Personalmente, yo diría que si la lógica del algoritmo requiere un comportamiento de iteración normalmente lineal, pero omitiendo o repitiendo ciertas iteraciones, vaya por ello. Sin embargo, también estoy de acuerdo con la mayoría de las personas en que esto no es normal para el uso del bucle, así que si estuviera en su lugar, me aseguraría de incluir una o dos líneas de comentarios que indiquen POR QUÉ está sucediendo.

Un caso de uso perfectamente válido para tal cosa podría ser analizar una cadena de números romanos. Para cada índice de caracteres en la cadena, mira ese carácter y el siguiente. Si el valor numérico del siguiente carácter es mayor que el carácter actual, reste el valor del carácter actual del siguiente, agregue el resultado al total y saltee el siguiente carácter al incrementar el índice actual. De lo contrario, simplemente agregue el valor del carácter actual al total acumulado y continúe.

Cuestiones relacionadas