Estructuras de control

Las estructuras de control son construcciones sintácticas que determinan la lógica y el orden de cómo ocurren las operaciones de nuestro programa, es decir, dirijen el flujo de éstas y controlan la ejecución del código en una dirección u otra. Para ello, es fundamental establecer condicionales en el código.

Construcciones if - else

Esta sintaxis inglesa realiza la función de lo que literalmente se traduce de ella. Esto es, "si" y "de otro modo", para if y else, respectivamente. De una forma más concreta, se entiende como "si esta condición es TRUE, ejecuta la siguiente operación, de otro modo ejecuta ésta otra". La construcción dentro del programa se incluiría así:

1
2
3
4
5
if(condición) {
  operaciones_si_condición=TRUE
} else {
  operaciones_si_condición=FALSE
}

No obstante, la construcción puede incluir únicamente if, para indicar que se ejecute una operación si se cumple la condición, sino se continúa con el programa.

1
2
3
if(condición) {
  operaciones_si_condición=TRUE
}

Ejemplo

1
2
3
4
euros <- -20
if (euros < 0){
  print("Estás en números negativos")
}

Si bien, es cierto que podría escribirse del siguiente modo:

1
2
if(condición) {operaciones_si_condición=TRUE
} else {operaciones_si_condición=FALSE}

Las operaciones se deben incluir solamente en una expresión, por lo que si hay más de una operación se conectan mediante el operador ; o pasando al siguiente renglón y manteniendo la iteración.

1
2
3
4
5
6
if(condición) {
  operación1_si_condición=TRUE
  operación2
} else {
  operaciones_si_condición=FALSE
}

Por otro lado, la contrucción podría componerse de múltiples condiciones. Para ello, junto a else se sitúa de nuevo if.

1
2
3
4
5
6
7
if(condición1) {
  operaciones_si_condición=TRUE
} else if(condición2) {
  operaciones_si_condición1=FALSE_condición2=TRUE
} else { 
operaciones_si_condiciones=FALSE
}

Ejemplo

1
2
3
4
5
6
7
8
9
num_real <- 5.43
num_entero <- -10
if(num_real < num_entero) {
  "condición1-TRUE"
} else if(num_real > num_entero & num_entero > num_integer) {
  "condición2-TRUE"
} else {
  "condiciones-FALSE"
}

Hasta ahora, las construcciones mencionadas no permiten incluir secuencias o vectores. Si bien, la función ifelse() se emplea para controlar el flujo en esta estructura de datos, lo que también incluye valores independientes, sin necesidad de conformar una secuencia. Esta función nos devuelve un vector con los valores correspondientes para cada elemento del vector tras realizar su respectiva operación, atendiendo a las condiciones interpuestas.

Ejemplo

1
ifelse1 <- ifelse(c(3,4,5,6,7) < num_real, "condición-TRUE", "condición-FALSE")

Cree un script llamado sup_inf_igual_0.R que indique si el número introducido es superior, inferior, o igual a 0.

Respuesta
1
2
3
4
5
6
7
8
9
print ("Número que desea conocer cómo es respecto a 0: ")
num <- scan(n=1)
if (num==0) {
  cat(num, "es igual a 0.")
} else if (num<0) {
  cat(num, "es menor que 0.")
} else {
  cat(num, "es mayor que 0.")
}

Bucles for

Este tipo de construcciones repite las operaciones que contiene un número determinado de veces, las cuales se indican entre paréntesis y corresponden al número de veces que se observa un elemento en la estructura de datos que introduzcamos. Las operaciones se pueden llevar a cabo con el elemento en cuestión, al cual se le puede nombrar como guste, siendo común la letra i o una palabra descritiva. En cuanto a la estructura de datos, debe de ser un objeto ya existente o que se formule en la construcción, cuyo modelo es el siguiente:

1
2
3
for(elemento in estructura){
  operaciones_con/sin_elemento
}

Ejemplos

1
2
3
4
5
6
7
for (i in 1:10){
  print(i)
}
lista1 <- list(equipo="verde", componentes=2, nombres=c("Ana", "Juan"), ganador=TRUE) 
for(i in lista1) {
  i
}

Info

Los bucles no devuelven los resultados a no ser que se lo indiques explícitamente con funciones como print(). Además, si se pretende asignar los resultados a una variable, ésta debe de haber sido declarada previamente, y se utiliza el operador [], de forma que la estructura de datos contenida en la variable aumentaría su longitud por cada repetición.

1
2
3
4
vector_for1 <- 1
for(i in 2:7) {
  vector_for1[i] <- i
}

Hay que tener cuidado con las estructuras que empleamos en el bucle y los datos que contienen, ya que podrían devolver errores o resultados no esperados cuando se mezclan tipos de datos en ellas. Esto y la simplicidad y velocidad de cómputo que ofrecen otras opciones de R, hacen que este bucle no sea tan utilizado.

1
2
3
4
vector_for2 <- NULL
for(i in list(1:4, 6, 8, "c", "a")) {
  vector_for2[i] <- i
}

Cree un script fibonacci.R que devuelva la sucesión de Fibonacci del número indicado.

Respuesta
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
print("Introduzca un número: ")
n <- scan(n=1)
a <- 0
b <- 1
cat("Los", n, "primeros números de la sucesión de Fibonacci son:", "\n")
for (i in 1:n) {
  a <- a+b
  b <- a-b
  cat("El número de la posición", i, "es", a, "\n")
}

Bucles while

Este tipo de bucle repite las operaciones mientras la condición impuesta sea TRUE. El modelo para lograr esta contrucción es el siguiente:

1
2
3
while(condicion) {
  operaciones_si_condicion=TRUE
}

Si realizásemos el modelo tal cual se ha mostrado y la condición sea siempre TRUE, se produciría un bucle infinito , el cual se abandona presionando la tecla ESC si estás en RStudio, o ctrl + c para la terminal, ya que se podría congelar el ordenador. Por ello, es necesario operar con los objetos que formen parte de la condición, de forma que en un momento la condición sea FALSE y pare el bucle.

Ejemplo

1
2
3
while(num_real > 1 | num_entero < num_real) {
  num_real <- num_real - 3
}

Cree un script llamado suma_enteros_100.R que realice la suma de los números enteros comprendidos entre el número indicado y 100.

Respuesta
1
2
3
4
5
6
7
8
print("Indique un número entre 0 y 100: ")
suma <- 0
n <- scan(n=1)
while (n<=100){
  suma <- suma+n
  n <- n+1
}
cat("El valor de la suma de enteros hasta 100 es", suma)

Break, Next y bucles repeat

Las estructuras de control break y next son palabras reservadas que no pueden emplearse como variable. Ambas se utilizan dentro de otras estructuras de control y requieren que una condición sea TRUE para que se efectúe su acción, que para break es finalizar el bucle, mientras que next avanza a la siguiente iteración sin realizar operación. De hecho, break es necesario para no caer en un bucle infinito creado con la estructura repeat, la cual no se usa con frecuencia. Si bien, el modelo de este bucle es el siguiente:

1
2
3
4
repeat{
  operaciones
  break
}

Ejemplos

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
repeat{
  num_real <- num_real / 2
  if(num_real > -4) {
    break
  }
}
vector11 <- c()
for(i in vector_for1) {
  if(i == 6) {
    next
  }
  vector11[i] <- vector_for1[i] * 2
}
while(num_entero != 6) {
  if(num_entero == 5) {
    break
  }
  num_entero <- num_entero + 5
}

Modifique el script suma_enteros_100.R de forma que ignore el valor 50 y finalice el programa si la suma supera el valor 2000.

Respuesta
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
print("Indique un número entre 0 y 100: ")
suma <- 0
n <- scan(n=1)
for(i in n:100){
  if(i==50){
    next
  }
  if(suma>2000){
    break
  }
  suma <- suma + i
}
cat("El valor de la suma de enteros hasta que supera por primera vez el valor 2000 es", suma)

Declaraciones switch

Este tipo de construcción permite al usuario elegir la operación que se llevaría a cabo al ejecutar el código. Para ello, se debe incluir una función de entrada como readline() tras una de salida que muestre información sobre las opciones. Por lo tanto, presentaría la forma siguiente:

1
2
3
4
5
6
7
print("Opciones: a, b y c)
eleccion <- readline(prompt="Elija una de las anteriores opciones: ")
switch(eleccion,
  a=operación_a,
  b=operación_b,
  c=operación_c,
  stop("Opción no válida"))

Ejemplo

1
2
3
4
5
6
print("La operación log(20) + 4*7 >= 2^5 | length(c(1:6)) <= log10(6^8) es TRUE.")
respuesta <- readline(prompt="¿Es cierta la afirmación anterior?  (a=Verdadero, b=Falso): ")
switch(respuesta,
  a=print("Correcto"),
  b=print("Incorrecto"),
  stop("Opción no válida"))

Cree un script llamado elegir_script.R que te ofrezca la oportunidad de elegir ejecutar el script fibonacci, o suma_enteros_100.R

Respuesta
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
print("Opciones:")
print("A. sup_inf_igual_0.R")
print("B. suma_enteros_100.R")
print("C. fibonacci.R")
eleccion <- readline(prompt="Elija el script que desee ejecutar: ")
switch(eleccion,
  A=source("sup_inf_igual_0.R"),
  B=source("fibonacci.R"),
  C=source("suma_enteros_100.R",
  stop("Opción no válida"))

Ejercicios complementarios

Cree un script llamado tabla_mult_completo.R que devuelva la tabla de multiplicar del número deseado.

Respuesta
1
2
3
4
5
print("¿De qué número desea conocer su tabla de multiplicar? ")
num <- scan(n=1)
for (i in 0:10){
  cat (num, "*", i, "=", i*num, "\n")
}

Cree, recurriendo a nota_media.R, un script llamado sobresalientes.R que devuelva una lista con los alumnos de clase cuya media es de sobresaliente.

Respuesta
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
print("Número de alumnos en clase:")
num_alumnos <- scan(n=1)
sobresalientes <- c()
for(i in 1:num_alumnos){
  source("nota_media.R")
  if(lista$nota_media >= 9) {
    sobresalientes[i] <- lista$nombre
  } 
}
lista_sb <- list(alumnos_sobresalientes=sobresalientes)
print(lista_sb)

Cree un script llamado juego_adivinar_num.R que permita jugar a adivinar un número aleatorio del 1 al 10. ¿Serías capaz de crear un cuaderno de R donde expliques el programa?

Respuesta
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
secreto <- sample(1:10,1)
found <- TRUE            
while(found){
  print("Prueba un número: ")
  n <- scan(n=1)
  if (n<secreto) {
    print("El numero que has pensado es mayor")
  } else {
    print ("El numero que has pensado es menor")
  }
  if (n==secreto){
    print("¡ACERTASTE!")
    break
  }
}

Consulta en el siguiente fichero si tu cuaderno es correcto: juego_adivinar.Rmd