Pregunta

Al revisar, a veces encuentro este tipo de bucle:

i = begin
while ( i != end ) {    
   // ... do stuff
   if ( i == end-1 (the one-but-last element) ) {
      ... do other stuff
   }
   increment i
}

Luego hago la pregunta: ¿escribirías esto?

i = begin
mid = ( end - begin ) / 2 // (the middle element)
while ( i != end ) {    
   // ... do stuff
   if ( i > mid ) {
      ... do other stuff
   }
   increment i
}

En mi opinión, esto supera la intención de escribir un bucle: bucle porque hay algo común que hacer para cada uno de los elementos. Usando esta construcción, para algunos de los elementos haces algo diferente. Entonces, concluyo, necesita un bucle separado para esos elementos:

i = begin
mid = ( end - begin ) / 2 //(the middle element)
while ( i != mid ) {    
   // ... do stuff
   increment i
}

while ( i != end ) {
   // ... do stuff
   // ... do other stuff
   increment i
}

Ahora incluso vi una pregunta sobre SO sobre cómo escribí la cláusula if de una manera agradable ... Y me puse triste: algo no está bien aquí.

¿Estoy equivocado? Si es así, ¿qué hay de bueno en abarrotar el cuerpo del bucle con casos especiales, que usted conoce por adelantado, en el momento de la codificación?

¿Fue útil?

Solución

@xtofl,

Estoy de acuerdo con tu preocupación.

Millones de veces me encontré con un problema similar.

Cualquiera de los desarrolladores agrega un manejo especial para el primer o el último elemento.

En la mayoría de los casos vale la pena simplemente pasar del elemento startIdx + 1 al elemento endIdx - 1 o incluso dividir un ciclo largo en múltiples ciclos más cortos.

En casos muy raros, no es posible dividir el bucle.

En mi opinión, las cosas poco frecuentes deben manejarse fuera del ciclo siempre que sea posible.

Otros consejos

No creo que esta pregunta deba responderse por un principio (por ejemplo, " en un bucle, trate a cada elemento por igual ") En cambio, puede ver dos factores para evaluar si una implementación es buena o mala:

  1. Efectividad en tiempo de ejecución: ¿el código compilado se ejecuta rápidamente o sería más rápido hacerlo de manera diferente?
  2. Mantenimiento del código: ¿es fácil (para otro desarrollador) entender lo que está sucediendo aquí?

Si es más rápido y el código es más legible haciendo todo en un bucle, hágalo de esa manera. Si es más lento y menos legible, hágalo de otra manera.

Si es más rápido y menos legible, o más lento pero más legible, descubra cuál de los factores es más importante en su caso específico y luego decida cómo hacer un bucle (o no).

Sé que he visto esto cuando las personas intentaron unir elementos de una matriz en una cadena separada por comas:

for(i=0;i<elements.size;i++) {
   if (i>0) {
     string += ','
   }
   string += elements[i]
}

O bien tiene esa cláusula if allí, o debe duplicar la cadena + = línea nuevamente al final.

La solución obvia en este caso es

string = elements.join(',')

Pero el método de unión hace el mismo bucle internamente. Y no siempre hay un método para hacer lo que quieres.

Me di cuenta de que cuando pongo casos especiales en un bucle for, generalmente soy demasiado inteligente para mi propio bien.

En el último fragmento que publicó, está repitiendo el código para // .... hacer cosas.

Tiene sentido mantener 2 bucles cuando tiene un conjunto de operaciones completamente diferente en un conjunto diferente de índices.

i = begin
mid = ( end - begin ) / 2 //(the middle element)
while ( i != mid ) {    
   // ... do stuff
   increment i
}

while ( i != end ) {
   // ... do other stuff
   increment i
}

Este no es el caso, aún querría mantener un solo bucle. Sin embargo, el hecho es que aún guarda (fin - comienzo) / 2 número de comparaciones. Por lo tanto, se reduce a si desea que su código se vea ordenado o si desea guardar algunos ciclos de CPU. La llamada es tuya.

Creo que lo tienes completamente clavado. La mayoría de las personas caen en la trampa de incluir ramas condicionales en bucles, cuando podrían hacerlo afuera: lo cual es simplemente más rápido .

Por ejemplo:

if(items == null)
    return null;

StringBuilder result = new StringBuilder();
if(items.Length != 0)
{
    result.Append(items[0]); // Special case outside loop.
    for(int i = 1; i < items.Length; i++) // Note: we start at element one.
    {
        result.Append(";");
        result.Append(items[i]);
    }
}
return result.ToString();

Y el caso del medio que describió es simplemente desagradable . Imagine si ese código crece y necesita ser refactorizado en diferentes métodos.

A menos que esté analizando XML < grin > los bucles deben mantenerse tan simples y concisos como sea posible.

Creo que tienes razón acerca de que el ciclo está destinado a tratar todos los elementos por igual. Desafortunadamente, a veces hay casos especiales y estos deben tratarse dentro de la construcción del bucle a través de declaraciones if.

Si hay muchos casos especiales, aunque probablemente deberías pensar en encontrar alguna forma de lidiar con los dos conjuntos diferentes de elementos en construcciones separadas.

Prefiero simplemente, excluir el elemento del bucle y dar un tratamiento separado fuera del circuito

Por ejemplo: Consideremos el caso de EOF

i = begin
while ( i != end -1 ) {    
   // ... do stuff for element from begn to second last element
   increment i
}

if(given_array(end -1) != ''){
   // do stuff for the EOF element in the array
}

Por supuesto, las cosas con carcasa especial en un bucle que se pueden extraer es una tontería. Sin embargo, tampoco duplicaría el do_stuff; Lo pondría en una función o en una macro para no copiar y pegar el código.

Otra cosa que odio ver es el patrón para caso :

for (i=0; i<5; i++)
{
  switch(i)
  {
    case 0:
      // something
      break;
    case 1:
      // something else
      break;
    // etc...
  }
}

He visto esto en código real.

¿Cuál funciona mejor?

Si la cantidad de elementos es muy grande, siempre haría un ciclo, especialmente si va a realizar alguna operación en cada elemento. Es probable que el costo de evaluar el condicional sea menor que hacer un bucle dos veces.

Vaya, por supuesto que no estás haciendo un bucle dos veces ... En cuyo caso, es preferible dos bucles. Sin embargo, mantengo que la consideración principal debería ser el rendimiento. No es necesario incurrir en el condicional en el bucle (N veces) si puede dividir el trabajo mediante una simple manipulación de los límites del bucle (una vez).

El caso especial debe hacerse fuera del ciclo si solo se realiza una vez.

Sin embargo, puede haber un índice o alguna otra variable (s) que son más fáciles de mantener dentro del ciclo debido al alcance. También puede haber una razón contextual para mantener todas las operaciones en la estructura de datos juntas dentro de la estructura de control de bucle, aunque creo que es un argumento débil por sí solo.

Se trata de usarlo según las necesidades y la conveniencia. Como tal, no hay menciones para tratar los elementos por igual y, desde luego, no hay ningún daño en las características del lenguaje.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top