Mi profesor mencionó hoy que era posible "etiquetar" los bucles en Java para que pudiera referirse a ellos cuando se trata de bucles anidados. Así que busqué la función, ya que no lo sabía y en muchos lugares donde se explicó esta función fue seguida por una advertencia, desalentando los bucles anidados.
Realmente no entiendo por qué? ¿Es porque afecta la legibilidad del código? ¿O es algo más "técnico"?
java
readability
loops
DSF
fuente
fuente
Respuestas:
Los bucles anidados están bien siempre que describan el algoritmo correcto.
Los bucles anidados tienen consideraciones de rendimiento (consulte la respuesta de @ Travis-Pesetto), pero a veces es exactamente el algoritmo correcto, por ejemplo, cuando necesita acceder a cada valor en una matriz.
Etiquetar bucles en Java permite romper prematuramente varios bucles anidados cuando otras formas de hacerlo serían engorrosas. Por ejemplo, algunos juegos pueden tener un código como este:
Si bien el código como el ejemplo anterior a veces puede ser la forma óptima de expresar un cierto algoritmo, generalmente es mejor dividir este código en funciones más pequeñas, y probablemente usarlo en
return
lugar debreak
. Entonces, unabreak
etiqueta tiene un olor a código débil ; presta especial atención cuando lo veas.fuente
Los bucles anidados son con frecuencia (pero no siempre) una mala práctica, porque con frecuencia (pero no siempre) son excesivos para lo que estás tratando de hacer. En muchos casos, hay una forma mucho más rápida y menos derrochadora de lograr el objetivo que está tratando de lograr.
Por ejemplo, si tiene 100 elementos en la lista A y 100 elementos en la lista B, y sabe que para cada elemento en la lista A hay un elemento en la lista B que coincide, (con la definición de "coincidencia" deja deliberadamente oscuro aquí), y desea producir una lista de pares, la forma simple de hacerlo es así:
Con 100 elementos en cada lista, esto requerirá un promedio de 100 * 100/2 (5,000)
matches
operaciones. Con más elementos, o si la correlación 1: 1 no está asegurada, se vuelve aún más costosa.Por otro lado, hay una forma mucho más rápida de realizar una operación como esta:
Si lo hace de esta manera, en lugar de la cantidad de
matches
operaciones en que se basalength(A) * length(B)
, ahora se basa enlength(A) + length(B)
, lo que significa que su código se ejecutará mucho más rápido.fuente
O(n log n)
dos veces, si se usa Quicksort.O(n^2)
para los valores no pequeños de N.<
operador, que generalmente no puede derivarse delmatches
operador. En segundo lugar, incluso si X e Y son numéricos, el segundo algoritmo aún puede producir resultados incorrectos, por ejemplo, cuando loX matches Y
esX + Y == 100
.Una razón para evitar anidar bucles es porque es una mala idea anidar estructuras de bloques con demasiada profundidad, independientemente de si son bucles o no.
Cada función o método debe ser fácil de entender, tanto su propósito (el nombre debe expresar lo que hace) como para los mantenedores (debe ser fácil de entender lo interno). Si una función es demasiado complicada para comprenderla fácilmente, eso generalmente significa que algunas de las funciones internas se deben descomponer en funciones separadas para que se pueda hacer referencia a ellas en la función principal (ahora más pequeña) por nombre.
Los bucles anidados pueden ser difíciles de entender con relativa rapidez, aunque algunos anidamientos de bucles están bien, ya que, como otros señalan, eso no significa que esté creando un problema de rendimiento al usar un algoritmo extremadamente lento (e innecesariamente).
En realidad, no necesita bucles anidados para obtener límites de rendimiento absurdamente lentos. Considere, por ejemplo, un solo bucle que en cada iteración toma un elemento de una cola y luego posiblemente devuelve varios, por ejemplo, la búsqueda en primer plano de un laberinto. El rendimiento no se decide por la profundidad de anidamiento del bucle (que es solo 1) sino por el número de elementos que se colocan en esa cola antes de que finalmente se agote ( si alguna vez se agota): cuán grande es la parte alcanzable del bucle Laberinto es.
fuente
Dado el caso de muchos bucles anidados, terminas con tiempo polinómico. Por ejemplo, dado este pseudocódigo:
Esto se consideraría O (n ^ 2) tiempo, que sería un gráfico similar a:
Donde el eje y es la cantidad de tiempo que su programa tarda en terminar y el eje x es la cantidad de datos.
Si obtiene demasiados datos, su programa será tan lento que nadie lo esperará. y no es tanto alrededor de 1,000 entradas de datos, creo que tomará demasiado tiempo.
fuente
Conducir un camión de treinta toneladas en lugar de un pequeño vehículo de pasajeros es una mala práctica. Excepto cuando necesite transportar 20 o 30 toneladas de cosas.
Cuando usa un bucle anidado, no es una mala práctica. Es completamente estúpido o es exactamente lo que se necesita. Tú decides.
Sin embargo, alguien se quejó de etiquetar los bucles. La respuesta para eso: si tiene que hacer la pregunta, entonces no use el etiquetado. Si sabes lo suficiente como para decidirte, entonces tú decides.
fuente
No hay nada intrínsecamente malo o necesariamente malo en los bucles anidados. Sin embargo, tienen ciertas consideraciones y dificultades.
Los artículos a los que se dirigió, probablemente en nombre de la brevedad o debido a un proceso psicológico conocido como quemado, omitiendo los detalles.
Quemarse es cuando tienes una experiencia negativa de algo con el ser implicado y luego lo evitas. Por ejemplo, podría cortar vegetales con un cuchillo afilado y cortarme yo mismo. Entonces podría decir que los cuchillos afilados son malos, no los use para cortar vegetales para tratar de hacer imposible que esa mala experiencia vuelva a suceder. Eso es obviamente muy poco práctico. En realidad solo necesitas tener cuidado. Si le estás diciendo a otra persona que corte las verduras, entonces tienes un sentido aún más fuerte de esto. Si les dijera a los niños que cortaran vegetales, me gustaría mucho decirles que no usen un cuchillo afilado, especialmente si no puedo supervisarlos de cerca.
El problema con la programación es que no alcanzará la máxima eficiencia si siempre prefiere la seguridad primero. En este caso, los niños solo pueden cortar vegetales blandos. Enfrentados con cualquier otra cosa y solo lo arruinarán con un cuchillo sin filo. Es importante aprender el uso adecuado de los bucles, incluidos los bucles anidados, y no puede hacerlo si se consideran malos y nunca intenta usarlos.
Como muchas respuestas aquí señalan, un bucle anidado es una indicación de las características de rendimiento de su programa que pueden empeorar exponencialmente cada anidación. Es decir, O (n), O (n ^ 2), O (n ^ 3) y así sucesivamente, que comprende O (n ^ profundidad) donde la profundidad representa cuántos bucles ha anidado. A medida que crece su anidación, el tiempo requerido crece exponencialmente. El problema es que esto no es una certeza de que su complejidad de tiempo o espacio sea eso (a menudo a * b * c pero no todos los bucles de nido pueden ejecutarse todo el tiempo tampoco) ni es una certeza de que tener un problema de rendimiento incluso si es eso.
Para muchas personas, especialmente estudiantes, escritores y profesores que, para ser francos, rara vez programan para ganarse la vida o en el día a día para bucles, también pueden ser algo a lo que no están acostumbrados y que indujeron demasiada carga cognitiva en los primeros encuentros. Este es un aspecto problemático porque siempre hay una curva de aprendizaje y evitarla no será eficaz para convertir a los estudiantes en programadores.
Los bucles anidados pueden volverse salvajes, es decir, pueden terminar anidados muy profundamente. Si paso por cada continente, luego por cada país, luego por cada ciudad, luego por cada tienda, luego por cada estante, luego por cada producto si es una lata de frijoles por cada frijol y mido su tamaño para obtener el promedio, entonces usted puede ver que anidará muy profundamente. Tendrás una pirámide y mucho espacio desperdiciado lejos del margen izquierdo. Incluso puede terminar saliendo de la página.
Este es un problema que sería más significativo históricamente donde las pantallas eran pequeñas y de baja resolución. En esos casos, incluso unos pocos niveles de anidación podrían realmente ocupar mucho espacio. Esta es una preocupación menor hoy en día donde el umbral es más alto, aunque todavía puede presentar un problema si hay suficiente anidamiento.
Relacionado está el argumento de la estética. Muchas personas no encuentran que los bucles anidados sean estéticamente agradables en contraste con los diseños con una alineación más consistente, esto puede o no estar relacionado con lo que las personas están acostumbradas, el seguimiento ocular y otras preocupaciones. Sin embargo, es problemático porque tiende a reforzarse a sí mismo y, en última instancia, puede hacer que el código sea más difícil de leer, ya que romper un bloque de código y encapsular bucles detrás de abstracciones como funciones también corre el riesgo de romper el mapeo del código al flujo de ejecución.
Hay una tendencia natural hacia lo que la gente está acostumbrada. Si está programando algo de la manera más simple, la probabilidad de no necesitar anidamiento es mayor, la probabilidad de necesitar un nivel disminuye en un orden de magnitud, la probabilidad de que otro nivel disminuya nuevamente. La caída de frecuencia y esencialmente significa que cuanto más profundo es el anidamiento, menos capacitados están los sentidos humanos para anticiparlo.
Relacionado con eso, es que en cualquier construcción compleja, que se puede considerar un bucle anidado, siempre debe preguntar es la solución más simple posible, ya que existe el potencial para una solución perdida que necesita menos bucles. La ironía es que una solución anidada a menudo es la forma más sencilla de producir algo que funcione con la mínima cantidad de esfuerzo, complejidad y carga cognitiva. A menudo es natural anidar para bucles. Si considera, por ejemplo, una de las respuestas anteriores donde la forma mucho más rápida que un bucle for anidado también es mucho más compleja y consiste en un código significativamente más.
Se necesita una gran cantidad de atención, ya que a menudo es posible abstraer los bucles o aplanarlos, pero el resultado final es una cura peor que la enfermedad, especialmente si no está recibiendo, por ejemplo, una mejora del rendimiento cuantificable y significativa.
Es muy común que las personas experimenten con frecuencia problemas de rendimiento en asociación con bucles que le dicen a la computadora que repita una acción muchas veces y que a menudo estarán implicados en cuellos de botella de rendimiento. Lamentablemente, las respuestas a esto pueden ser muy superficiales. Es común que las personas vean un bucle y vean un problema de rendimiento donde no lo hay, y luego oculten el bucle de la vista sin ningún efecto real. El código "se ve" rápido pero lo pone en el camino, teclea el encendido, pisa el acelerador y mira el velocímetro y es posible que todavía sea tan rápido como una anciana que camina por su marco zimmer.
Este tipo de escondite es similar a si tienes diez asaltantes en tu ruta. Si en lugar de tener una ruta directa a donde quieres ir, la arreglas para que haya un atracador detrás de cada esquina, entonces te da la ilusión al comenzar tu viaje de que no hay atracadores. Fuera de la vista, fuera de la mente. todavía vas a ser asaltado diez veces, pero ahora no lo verás venir.
La respuesta a su pregunta es que son ambas, pero ninguna de las preocupaciones es absoluta. Son completamente subjetivos o solo contextualmente objetivos. Lamentablemente, a veces, la opinión totalmente subjetiva o más bien precede y domina.
Como regla general, si necesita un bucle anidado o ese parece ser el siguiente paso obvio, es mejor no deliberar y simplemente hacerlo. Sin embargo, si persisten las dudas, se debe revisar más adelante.
Otra regla general es que siempre debe verificar la cardinalidad y preguntarse si este bucle será un problema. En mi ejemplo anterior, pasé por ciudades. Para las pruebas, podría pasar por diez ciudades, pero ¿cuál es el número máximo razonable de ciudades que se pueden esperar en el uso en el mundo real? Entonces podría multiplicar eso por lo mismo para los continentes. Es una regla general considerar siempre con bucles, especialmente que iteran una cantidad dinámica (variable) de veces lo que eso podría traducirse en el futuro.
Independientemente, siempre haz lo que funciona primero. La forma en que ve una oportunidad para la optimización puede comparar su solución optimizada con la más fácil de conseguir y confirmar que produjo los beneficios esperados. También puede pasar demasiado tiempo optimizando prematuramente antes de que comiencen las mediciones y eso conduce a YAGNI o una gran cantidad de tiempo perdido y plazos vencidos.
fuente
n
, es geométrica o polinómica .