3 Estructuras de control
Como mencionamos anteriormente, un algoritmo está compuesto por una sucesión ordenada de comandos que se ejecutan uno detrás de otro. Sin embargo, con frecuencia es necesario recurrir a comandos especiales que alteran o controlan el orden en el que se ejecutan las acciones. Llamamos estructuras de control del flujo de las acciones al conjunto de reglas que permiten controlar el flujo de las acciones de un algoritmo o programa. Las mismas pueden clasificarse en secuenciales, condicionales e iterativas.
3.1 Estructuras de control secuenciales
Las estructuras secuenciales están compuestas por un número definido de acciones que se ubican en un orden específico y se suceden una tras otra. Los ejemplos que hemos discutido anteriormente están conformados por este tipo de estructura.
3.2 Estructuras de control condicionales
En algunas partes de un algoritmo puede ser útil detenerse a hacer una pregunta porque se llegó a una situación en la que puede haber una o más opciones disponibles para continuar. Dependiendo de la respuesta a la pregunta, que siempre deberá ser VERDADERO
(TRUE
) o FALSO
(FALSE
), el algoritmo seguirá ciertas acciones e ignorará otras. Estas preguntas y respuestas representan procesos de toma de decisión que conducen a diferentes caminos dentro del algoritmo, permitiéndonos que la solución para el problema en cuestión sea flexible y se adapte a distintas situaciones. Este tipo de estructuras de control de las acciones reciben el nombre de condicionales (o estructuras de selección) y pueden ser simples, dobles y múltiples.
3.2.1 Estructuras condicionales simples
Postulan una evaluación lógica y, si su resultado es VERDADERO
, se procede a ejecutar las acciones encerradas por esta estructura. Se describen en pseudocódigo con la siguiente sintaxis:
SI <condición> ENTONCES
Acción/es
FIN SI
La palabra SI
indica el comando de evaluación lógica, <condición>
indica la condición a evaluar y Acción/es
son las instrucciones que se realizarán sólo si se cumple la condición, es decir, si la evaluación resulta en VERDADERO
. Si la condición no se verifica, no se ejecuta ninguna acción y el algoritmo sigue su estructura secuencial a continuación del FIN SI
.
En R, la estructura que nos permite realizar esto es:
Por ejemplo, el siguiente algoritmo registra la edad de una persona y, en el caso de que sea mayor de edad, avisa que puede votar en las elecciones provinciales de Santa Fe:
ALGORITMO: "Analizar edad para votar"
COMENZAR
VARIABLE numérica edad
LEER edad
SI edad >= 18 ENTONCES
ESCRIBIR "Edad = " edad " años: puede votar"
FIN SI
FIN
# Programa: "Analizar edad para votar" -------------------------------
edad <- 21
if (edad >= 18) {
cat("Edad =", edad, "años: puede votar")
}
Edad = 21 años: puede votar
Notar que si bien el uso de sangrías en el código es opcional, decidimos emplearlo para facilitar su lectura. Mantener la prolijidad en nuestros programas es esencial.
3.2.2 Estructuras condicionales dobles
Este tipo de estructura añade una acción a ejecutarse en el caso de que la condición evaluada no se verifique (es decir, devuelve el valor FALSO
). La sintaxis es:
SI <condición> ENTONCES
Acción/es
SI NO
Acción/es
FIN SI
La palabra ENTONCES
antecede a las acciones que se realizan si se cumple la condición y la expresión SI NO
a las que se realizan si no se verifica la misma.
En R se utiliza el comando else
:
if (<condición>) {
...código para ejecutar acciones...
} else {
...código para ejecutar acciones...
}
Retomando el ejemplo anterior:
ALGORITMO: "Analizar edad para votar"
COMENZAR
VARIABLE numérica edad
LEER edad
SI edad >= 18 ENTONCES
ESCRIBIR "Edad = " edad " años: puede votar"
SI NO
ESCRIBIR "Edad = " edad " años: no puede votar"
FIN SI
FIN
# Programa: "Analizar edad para votar" -------------------------------
edad <- 21
if (edad >= 18) {
cat("Edad =", edad, "años: puede votar")
} else {
cat("Edad =", edad, "años: no puede votar")
}
Edad = 21 años: puede votar
3.2.3 Estructuras condicionales múltiples o anidadas
Permiten combinar varias estructuras condicionales para establecer controles más complejos sobre el flujo de las acciones, representando una toma de decisión múltiple. Podemos ejemplificar la sintaxis de la siguiente forma:
SI <condición 1> ENTONCES
Acción 1
SI NO
SI <condición 2> ENTONCES
Acción 2
SI NO
Acción 3
FIN SI
FIN SI
En la estructura anterior, hay una primera evaluación lógica en la cual si el resultado es VERDADERO
, se ejecuta la Acción 1 y nada más. En cambio, si su resultado es FALSO
, se procede a realizar una segunda evaluación lógica, que da lugar a la ejecución de la Acción 2 o de la Acción 3 si su resultado es VERDADERO
o FALSO
, respectivamente.
Se debe notar que luego del primer SI NO
comienza una nueva estructura completa de SI/ENTONCES/SI NO/FIN SI
. Cada SI
termina con su propio FIN SI
. Al traducir esto a R, se vuelve algo más sencillo:
if (<condición 1>) {
...Acción 1...
} else if (<condición 2>) {
...Acción 2...
} else {
...Acción 3...
}
El último bloque de acciones (...Acción 3...
) se evaluará si ninguna de las condiciones lógicas anteriores fue VERDADERO
.
En el ejemplo de la edad:
ALGORITMO: "Analizar edad para votar"
COMENZAR
VARIABLE numérica edad
LEER edad
SI edad < 18 ENTONCES
ESCRIBIR "Edad = " edad " años: no puede votar"
SI NO
SI edad >= 70 ENTONCES
ESCRIBIR "Edad = " edad " años: puede votar opcionalmente"
SI NO
ESCRIBIR "Edad = " edad " años: debe votar obligatoriamente"
FIN SI
FIN SI
FIN
# Programa: "Analizar edad para votar" -------------------------------
edad <- 21
if (edad < 18) {
cat("Edad =", edad, "años: no puede votar")
} else if (edad >= 70) {
cat("Edad =", edad, "años: puede votar opcionalmente")
} else {
cat("Edad =", edad, "años: debe votar obligatoriamente")
}
Edad = 21 años: debe votar obligatoriamente
3.3 Estructuras de control iterativas
Las estructuras de control iterativas son útiles cuando la solución de un problema requiere que se ejecute repetidamente un determinado conjunto de acciones. El número de veces que se debe repetir dicha secuencia de acciones puede ser fijo o puede variar dependiendo de algún dato o condición a evaluar en el algoritmo.
3.3.1 Estructuras de control iterativas con un número fijo de iteraciones
Se aplican cuando se conoce de antemano el número exacto de veces que se debe repetir una secuencia de acciones. También se conocen como bucles (loops) controlados por un conteo, ya que el algoritmo va contando la cantidad de repeticiones haciendo uso de una variable que recibe el nombre de variable de iteración, índice o conteo.
Por ejemplo, imaginemos que queremos escribir un algoritmo que permita calcular la quinta potencia de cualquier número. Para esto, se debe tomar dicho número y multiplicarlo por sí mismo 5 veces. Por lo tanto, una posible solución es:
ALGORITMO: "Calcular la quinta potencia"
COMENZAR
VARIABLE numérica x, resultado
LEER x
resultado <- 1
resultado <- resultado * x
resultado <- resultado * x
resultado <- resultado * x
resultado <- resultado * x
resultado <- resultado * x
ESCRIBIR x "elevado a la quinta es igual a" resultado
FIN
Ya que sabemos que la multiplicación se debe repetir 5 veces, podemos resumir lo anterior con la siguiente estructura:
ALGORITMO: "Calcular la quinta potencia"
COMENZAR
VARIABLE numérica x, resultado
LEER x
resultado <- 1
PARA i DESDE 1 HASTA 5 HACER
resultado <- resultado * x
FIN PARA
ESCRIBIR x "elevado a la quinta es igual a" resultado
FIN
La letra i
es la variable de iteración. Podríamos haber elegido otra letra u otra palabra en su lugar, pero emplear i
es una elección bastante común. En este ejemplo, su única función es ir contando la cantidad de veces que se repiten las acciones encerradas dentro de la estructura PARA/FIN PARA
. El bloque de instrucciones se repite tantas veces como i
tarde en llegar a 5 partiendo desde 1. Por convención, a la variable de iteración no la declaramos junto con las otras variables numéricas (como x
y resultado
).
En R, el ejemplo anterior se implementa así:
# Programa: "Calcular la quinta potencia" ------------------------
x <- 4
resultado <- 1
for (i in 1:5) {
resultado <- resultado * x
}
cat(x, "elevado a la quinta es igual a", resultado)
4 elevado a la quinta es igual a 1024
Dado que la variable de iteración toma un valor numérico que va cambiando en cada repetición del bloque, se puede aprovechar para hacer cuentas con el mismo. Por ejemplo, el siguiente algoritmo muestra la tabla del ocho:
ALGORITMO: "Mostrar tabla del 8"
COMENZAR
VARIABLE numérica resultado
PARA i DESDE 0 HASTA 10 HACER
resultado <- 8 * i
ESCRIBIR "8 x" i "=" resultado
FIN PARA
FIN
# Programa: "Mostrar tabla del 8" -------------------------------
for (i in 0:10) {
resultado <- 8 * i
cat("8 x", i, "=", resultado, "\n")
}
8 x 0 = 0
8 x 1 = 8
8 x 2 = 16
8 x 3 = 24
8 x 4 = 32
8 x 5 = 40
8 x 6 = 48
8 x 7 = 56
8 x 8 = 64
8 x 9 = 72
8 x 10 = 80
En lo anterior, \n
es un carácter especial que indica “salto de línea”. Si no lo agregamos, los mensajes se imprimirían uno al lado del otro en el mismo renglón:
# Programa: "Mostrar tabla del 8" -------------------------------
for (i in 0:10) {
resultado <- 8 * i
cat("8 x", i, "=", resultado)
}
8 x 0 = 08 x 1 = 88 x 2 = 168 x 3 = 248 x 4 = 328 x 5 = 408 x 6 = 488 x 7 = 568 x 8 = 648 x 9 = 728 x 10 = 80
De manera general, la sintaxis para este tipo de estructuras es:
PARA <variable> DESDE <valor1> HASTA <valor2> CON PASO <valor3> HACER
Acción/es
FIN PARA
Dado un valor inicial <valor1>
asignado a la <variable>
, esta se irá aumentando o disminuyendo según el paso <valor3>
hasta llegar a tomar el valor <valor2>
. Si no se indica el paso se asume que la variable de iteración aumenta de uno en uno. En R:
for (<variable> in seq(<valor1>, <valor2>, <valor3>)) {
...Acción/es...
}
Notar en el ejemplo de la quinta potencia que 1:5
es lo mismo que seq(1, 5, 1)
, pero podemos usar la función seq()
en otros contextos más complejos, donde la variable de iteración puede pegar otros saltos en lugar de uno en uno.
3.3.2 Estructuras de control iterativas con un número indeterminado de iteraciones
En otras circunstancias se puede necesitar repetir un bloque de acciones sin conocer con exactitud cuántas veces, si no que esto depende de algún otro aspecto del algoritmo. Las iteraciones pueden continuar mientras que o hasta que se verifique alguna condición, dando lugar a dos tipos de estructuras. Estos casos también se conocen como bucles (loops) controlados por una condición.
3.3.2.1 Mientras que
El conjunto de sentencias se repite mientras que se siga evaluando como VERDADERO
una condición declarada al inicio del bloque. Cuando la condición ya no se cumple, el proceso deja de ejecutarse. La sintaxis es:
MIENTRAS QUE <condición> HACER
Acción/es a repetir
FIN MIENTRAS
En R:
while (<condición>) {
...Acción/es a repetir...
}
Observaciones:
- La evaluación de la condición se lleva a cabo antes de cada iteración, incluso antes de ejecutar el código dentro del bloque por primera vez. Si la condición es
FALSO
inicialmente, entonces las acciones en el cuerpo de la estructura no se ejecutan nunca. - La evaluación de la condición sólo se lleva a cabo al inicio de cada iteración. Si la condición se vuelve
FALSO
en algún punto durante la ejecución de un bloque, el programa no lo nota hasta que se termine de ejecutar el bloque y la condición sea evaluada antes de comenzar la próxima iteración.
Veamos un ejemplo:
ALGORITMO: "Dividir un número por 2 hasta encontrar un valor menor que 0.01"
COMENZAR
VARIABLE numérica x
LEER x
MIENTRAS QUE x >= 0.01 HACER
x <- x / 2
ESCRIBIR x
FIN MIENTRAS
FIN
x <- 100
while (x >= 0.01) {
x <- x / 2
cat(x, "\n")
}
50
25
12.5
6.25
3.125
1.5625
0.78125
0.390625
0.1953125
0.09765625
0.04882812
0.02441406
0.01220703
0.006103516
3.3.2.2 Hasta que
A diferencia de la estructura MIENTRAS QUE, la estructura HASTA QUE repite el bloque de acciones hasta que se cumpla una condición, es decir, se ejecuta mientras que dicha condición sea evaluada como FALSA
. La sintaxis es:
REPETIR
Acción/es
HASTA QUE <condición>
Observación: con la estructura MIENTRAS QUE podría ser que el conjunto de sentencias nunca llegue a ejecutarse si desde partida la condición evaluada ya es falsa. Por el contrario, en la estructura HASTA QUE el proceso se realiza al menos una vez, dado que la condición se evalúa al final.
El ejemplo anterior empleando este tipo de estructura:
ALGORITMO: "Dividir un número por 2 hasta encontrar un valor menor que 0.01"
COMENZAR
VARIABLE numérica x
LEER x
REPETIR
x <- x / 2
ESCRIBIR x
HASTA QUE x < 0.01
FIN
En R este tipo de estructura se implementa con la sentencia repeat {}
. Si bien a continuación se muestra el correspondiente ejemplo, no vamos a utilizar esta estructura, debido a que su escritura es más compleja y a que generalmente es posible obtener el mismo resultado con un while () {}
.
x <- 100
repeat {
x <- x / 2
cat(x, "\n")
if (x < 0.01) break
}
50
25
12.5
6.25
3.125
1.5625
0.78125
0.390625
0.1953125
0.09765625
0.04882812
0.02441406
0.01220703
0.006103516
3.3.2.3 Loops infinitos
Con las sentencias de tipo MIENTRAS QUE
se debe tener mucha precaución, puesto que si la evaluación lógica no está bien especificada o nunca deja de ser evaluada como TRUE
, se incurre en un loop infinito: el programa nunca deja de repetir el bloque (al menos hasta que la máquina se tilde o se produzca un error por desbordamiento de memoria, por ejemplo).
La siguiente situación ilustra esto:
var <- 9
while (var < 10) {
var <- var - 1
cat("var =", var, "No puedo parar!!!\n")
}
var = 8 No puedo parar!!!
var = 7 No puedo parar!!!
var = 6 No puedo parar!!!
var = 5 No puedo parar!!!
var = 4 No puedo parar!!!
var = 3 No puedo parar!!!
var = 2 No puedo parar!!!
var = 1 No puedo parar!!!
var = 0 No puedo parar!!!
var = -1 No puedo parar!!!
...
En R se puede usar la instrucción break
para forzar la detención del proceso iterativo si se presenta alguna condición en particular8:
var <- 9
while (var < 10) {
var <- var - 1
cat("var =", var, "No puedo parar!!!\n")
if (var == -3) break
}
var = 8 No puedo parar!!!
var = 7 No puedo parar!!!
var = 6 No puedo parar!!!
var = 5 No puedo parar!!!
var = 4 No puedo parar!!!
var = 3 No puedo parar!!!
var = 2 No puedo parar!!!
var = 1 No puedo parar!!!
var = 0 No puedo parar!!!
var = -1 No puedo parar!!!
var = -2 No puedo parar!!!
var = -3 No puedo parar!!!
3.4 Ejemplos
A continuación se presentan algunos otros ejemplos
-
No necesariamente tiene que ser
i
la variable iteradora, podemos darle cualquier nombre:for (guau in 1:5) { print(guau) }
[1] 1 [1] 2 [1] 3 [1] 4 [1] 5
La sentencia
print()
también sirve para mostrar resultados. La ventaja con respecto acat()
es que no necesitamos agregar\n
para que el siguiente mensaje se escriba en un nuevo renglón, ya que lo agrega por sí sola sin que lo pidamos. La desventaja es que no nos permite crear un mensaje combinando elementos separados entre comas, tal como se puede hacer concat()
(por ejemplo,cat("El valor de x es igual a", x)
). -
Acá tenemos un ejemplo de dos estructuras
for
anidadas. En primer lugar,i
toma el valor 1, y entoncesj
varía de 1 a 2, generando las combinacionesi = 1, j = 1; i = 1, j = 2
. Luego de que el loop dej
finalice habiendo recorrido todo su campo de variación, comienza la segunda iteración del loop dei
, actualizándose su valor a 2 y comenzando otra vez el loop dej
, que varía de 1 a 2. Así, se generan las combinacionesi = 2, j = 1; i = 2, j = 2
. Finalmente, se actualizai
y pasa a valer 3, generando las combinacionesi = 3, j = 1; i = 3, j = 2
. Para cada combinación, se muestra el valor de la suma:for (i in 1:3) { for (j in 1:2) { suma <- i + j cat("i vale", i, "y j vale", j, ". La suma es igual a", suma, "\n") } }
i vale 1 y j vale 1 . La suma es igual a 2 i vale 1 y j vale 2 . La suma es igual a 3 i vale 2 y j vale 1 . La suma es igual a 3 i vale 2 y j vale 2 . La suma es igual a 4 i vale 3 y j vale 1 . La suma es igual a 4 i vale 3 y j vale 2 . La suma es igual a 5
-
Sumar los números naturales del 1 al 5:
suma <- 0 for (i in 1:5) { suma <- suma + i } suma
[1] 15
-
Sumar números naturales hasta que la suma pase el valor 100 y detenerse:
suma <- 0 i <- 1 while (suma < 100) { suma <- suma + i i <- i + 1 } suma
[1] 105
-
Escribir todos los múltiplos de 8 menores que 150:
ALGORITMO: "Múltiplos de 8 menores a 150" COMENZAR VARIABLE numérica multiplo multiplo <- 8 MIENTRAS QUE multiplo < 150 HACER ESCRIBIR multiplo multiplo <- multiplo + 8 FIN MIENTRAS FIN
# Programa: "Múltiplos de 8 menores a 150" ------------------------ multiplo <- 8 while (multiplo < 150) { print(multiplo) multiplo <- multiplo + 8 }
[1] 8 [1] 16 [1] 24 [1] 32 [1] 40 [1] 48 [1] 56 [1] 64 [1] 72 [1] 80 [1] 88 [1] 96 [1] 104 [1] 112 [1] 120 [1] 128 [1] 136 [1] 144