martes, mayo 22, 2012

Tutorial de desarrollo web, Parte XXXIII: El bucle "for"

¡Hola otra vez! Ya el tiempo que llevo en Berlín se nota, que de hecho, hoy ya estoy escribiéndoles un artículo del tutorial desde aquí. Lamento no haber dejado las resoluciones a los ejercicios de este anterior mes y pico, pero como sabréis si habéis leído los posts de los sábados (o incluso los de los domingos), actualmente el internet no es el mayor fuerte que tengo aquí. ¡Pero prometo dejarlos todos desde que tenga mejor conexión!
Bueno, sigamos por dónde nos quedamos. La semana pasada vimos cómo la sentencia condicional podíamos "evolucionarla" a "else if" y "switch", dos formas alternativas de atajar esas situaciones, haciéndolo bastante más sencillo en algunas ocasiones. Esta semana vamos a hacer lo mismo, pero con los bucles.
En muchas ocasiones, antes de crear un bucle, sabremos cuantas veces querremos que se repita la misma acción. No es necesario que lo sepamos en el momento de la programación, pero sí al menos justo antes de entrar al bucle. Por ejemplo:

var x = prompt("Introduzca un número positivo:");

cont = 0;

while(cont <= x)
{
document.write(cont++ + '<br/>');
}

Este código, bastante simplón, le pide al usuario un número y luego escribe todos los números desde el 0 hasta el número en cuestión. Como vemos, antes de entrar en el bucle sabíamos que este se repetiría "x" veces, y hemos creado la variable "cont" para que vaya contando desde 0 hasta "x", sumándole uno en cada pasada. Pero hay una forma más simple de hacer esto: con el bucle for:

var x = prompt("Introduzca un número positivo:");

for(var i = 0; i <= x; i++)
{
document.write(i + '<br/>');
}

Este código haría exactamente lo mismo que el anterior. ¿Qué significa eso? Veámoslo por partes:
  • El bucle "for" divide su paréntesis en 3 partes. En la primera declara una variable que, por costumbre de programadores, se suele llamar "i", y se le asigna un valor inicial, que habitualmente suele ser 0, pero en alguna ocasión puede que nos interese empezar en otro número.
  • La segunda parte del bucle for expresa la condición, tal como hacíamos en el bucle "while". Le decimos que queremos que el bucle se repita mientras "i" tenga un valor menor o igual que "x".
  • Finalmente le decimos cómo queremos que se incremente "i". En nuestro caso, un valor cada vez (por lo cual usamos el incremento). Podríamos haber puesto "++i" ó "i + 1" sin ningún problema, pero lo habitual es usar el incremento. De hecho, este bucle "for" es muy típico y de forma muy habitual lo usaréis así sin casi modificarlo (como mucho la variable a comparar con i, o tal vez quitarle el "=" de la condición, dejándolo sólo como "menor que").
Bastante sencillo, ¿no? Pues les aseguro que vais a usar el "for" incluso más que el "while".
Por supuesto, hay situaciones en las que el "for" no será útil. Por ejemplo, imaginemos que queremos que el usuario adivine un número.

var x = 7;

var y = 0;

while(y != x)
{
y = prompt('Introduzca un número del 1 al 10:');
if(y == x)
{
alert('¡Muy bien!');
}
else
{
alert('¡Mal! ¡Inténtelo de nuevo!');
}
}

En este caso, evidentemente, al comenzar no sabemos cuánto va a tardar el usuario en adivinar que el número es el 7. Sin embargo, este ejemplo nos sirve para dar un par de ejemplos curiosos.
En primer lugar, imaginemos que el usuario sólo puede tener 5 intentos para adivinar el número. En ese caso el bucle for podría tener algún sentido, aunque...

var x = 7;

for(var i = 0; i < 5; i++)
{
y = prompt('Introduzca un número del 1 al 10:');
if(y == x)
{
alert('¡Muy bien!');
}
else
{
alert('¡Mal! ¡Inténtelo de nuevo!');
}
}

Nos damos cuenta de que, si el usuario acierta antes de lo 5 intentos, a pesar de darle la enhorabuena, el programa vuelve a pedirle que introduzca un número hasta que haya gastado los 5 intentos. ¿Qué podemos hacer para evitar eso? Pues usar una palabrita que aprendimos la semana pasada: la palabra reservada break.

var x = 7;

for(var i = 0; i < 5; i++)
{
y = prompt('Introduzca un número del 1 al 10:');
if(y == x)
{
alert('¡Muy bien!');
break;
}
else
{
alert('¡Mal! ¡Inténtelo de nuevo!');
}
}

La palabra "break" siempre nos sacará fuera de la sentencia en la que estemos en ese momento. De este modo, si introducimos el "break" en un bucle, interrumpirá el bucle y seguirá la ejecución del programa después del bucle.
Sigamos con alternativas de este juego. Imaginemos ahora que vayamos a darle al usuario un número ilimitado de intentos (como al comienzo). Tenemos que volver a usar el bucle "while", pero, ¿os dais cuenta de que en el bucle "while" tenemos que inicializar la "y" a 0 antes de entrar en el bucle, mientras que en el "for" no, ya que no evalúa esa condición hasta después de haber entrado en el bucle?
Intentando explicarlo más claro: en el bucle "for", la condición para ver si seguimos en el bucle es que "i" sea menor que 5, ya que la condición del bucle son los intentos del usuario y no si ha acertado o no. De esta manera, "y" no se inializa hasta que no se hace el primer "prompt".
Sin embargo, en el bucle "while", como la idea es que tenga intentos ilimitados y salga del bucle cuando lo adivine, la "y" sí está en la condición, y debe estar inicializada antes de ser evaluada, así que antes de empezar el bucle tenemos que inicializarla a 0 y luego, en el primer "prompt", cambiar su valor. ¿No se podría hacer algo más eficiente?
Pues, efectivamente, se puede. Porque hay un tercer tipo de bucle, el conocido como bucle "do...while".

var x = 7;

do
{
y = prompt('Introduzca un número del 1 al 10:');
if(y == x)
{
alert('¡Muy bien!');
}
else
{
alert('¡Mal! ¡Inténtelo de nuevo!');
}
}
while(y != x)

Como vemos, esta alternativa nos permite recorrer el contenido del bucle la primera vez sin haber evaluado ninguna condición. O sea, cuando el programa encuentra la palabra "do", entra y ejecuta lo que encuentre hasta que se encuentre, más abajo, con el "while", momento en el que evalúa si la condición es verdadera o no y decide si el bucle se repetirá una segunda o tercera o n-ésima vez. De este modo nos hemos librado de inicializar la "y" antes de entrar en el bucle, ya que cuando entra en el "do" no se evalúa ninguna condición.
Sin embargo, podemos comprobar que la misma condición se evalúa dos veces, ya que, aunque no exactamente iguales, pero la condición del "if" y del "while" vienen siendo lo mismo. ¿No hay otra manera de optimizar esto para no estar evaluando una y otra vez lo mismo? Pues, efectivamente, lo hay, aunque esto más que algo nuevo es un truco que podríais haber deducido por vuestra cuenta con los conocimientos que tenéis hasta el momento:

var x = 7;

do
{
y = prompt("Introduzca un número del 1 al 10:");
if(y == x)
{
alert('¡Muy bien!');
break;
}
alert('¡Mal! ¡Inténtelo de nuevo!);
}
}
while(true)

Analicemos el código poco a poco.
  • En primer lugar, inicializamos, como llevamos haciendo todo el rato, la "x" a 7, que será el valor que el usuario deberá adivinar.
  • En segundo lugar entramos en el bucle "do...while" sin evaluar ninguna condición, tal como es este tipo de bucle.
  • Pedimos al usuario por "prompt" que introduzca un número.
  • Ahora evaluamos la única condición real. En caso de que el usuario haya adivinado, lo felicitamos con un "alert" y salimos del bucle mediante el "break".
  • No necesitamos usar un "else" ya que, al tener el "break", si seguimos dentro del bucle significará que el usuario no adivinó el número, y le soltamos por "alert" que lo intente de nuevo.
  • Finalmente, recordemos que tanto para sentencias condicionales como para bucles, las condiciones son operaciones lógicas que acaban dando un resultado booleano, de modo que nos saltamos toda la operación y le introducimos directamente "true" dentro del "while". De esta manera, el bucle se ejecutará infinitamente hasta que encontremos un "break", o sea, cuando el usuario adivine el número. Como ya he comentado alguna vez, hay que tener MUCHO cuidado con los bucles infinitos, siempre hay que encontrar alguna forma de que se pueda salir (sea mediante condición o mediante un "break").
Y, de momento, eso es todo lo que necesitamos saber sobre los bucles. No son todos los que hay (igual que aún tampoco sabemos todas las sentenias condicionales) pero son los que más necesitaréis de momento. Y ahora, aunque no esté publicando sus resoluciones (todo caerá), de todos modos aquí van unos ejercicios, ¡ya que esto no se aprende si no se practica!

EJERCICIO 1

En primer lugar, el primer programa que tendremos que desarrollar esta semana pedirá al usuario un número del 1 al 10 y escribirá la tabla de multiplicar de dicho número, en un formato parecido al de los primeros ejercicios que hicimos.

EJERCICIO 2

En segundo lugar, modificaremos el anterior programa para ir escribiendo toda la tabla de multiplicar pero, a cada número, se pare a preguntar al usuario si quiere ver la siguiente línea. Mientras el usuario no diga que no, debe seguir escribiendo el siguiente número de la tabla infinitamente.

Y eso es todo por esta semana, la semana que viene esto empezará a ponerse realmente serio, así que recomendaría tener bastante claro todo lo que hemos dado hasta el momento, ya que lo necesitaréis. ¡Pásenlo bien!

1 comentario:

hormigon impreso en madrid dijo...

Gracias, muy bien explicado,es excelente este sitio un saludo.