Estructuras Condicionales
Las estructuras condicionales permiten la ejecución condicional de bloques de código.
La instrucción if
, que en inglés tiene el mismo significado que nuestro "si" condicional,
permite evaluar una expresión y, sobre la base de su resultado (verdadero o falso), ejecutar
o no la instrucción o el bloque que le sigue. Es decir, si el resultado de la expresión es
verdadero, ejecuta el código. En caso contrario, el programa sigue su curso normal.
A continuación, mostramos el diagrama de flujo de if
. En términos de diagramas de flujo, los rectángulos significan la realización de un proceso, en otras palabras la ejecución de un bloque de instrucciones. Por otro lado, los rombos son conocidos como símbolos de decisión, es decir se corresponden a preguntas cuyas respuestas únicamente tienen dos posibles respuestas, concretamente, TRUE (T) o FALSE (F).
La instrucción if
toma un valor lógico (en realidad, un vector lógico de longitud uno)
y ejecuta la siguiente instrucción sólo si el valor es TRUE
:
if (TRUE) {
message("Es verdadero, se ejecutara la instruccion.")
}
## Es verdadero, se ejecutara la instruccion.
if (FALSE) {
message("Es falso, no se ejecutara la instruccion.")
}
En el caso que pasemos valores desconocidos (NA
) a if
, R lanzará un error:
if (NA) {
message("Los valores desconocidos lanzan un error")
}
## Error in if (NA) {: missing value where TRUE/FALSE needed
Si nos encontramos ante esta situación, deberíamos comprobarlo mediante la función is.na()
:
if (is.na(NA)) {
message("El valor es desconocido.")
}
## El valor es desconocido.
Desde luego, en nuestro código en pocas ocasiones pasaremos los valores
TRUE
y FALSE
a la instrucción if
. En su lugar, pasaremos una variable o
expresión. En el siguiente ejemplo, runif(1)
genera un número de forma aleatoria
entre 0 y 1. Si el valor es mayor que 0.5
, entonces el mensaje será mostrado:
if (runif(1) > 0.5) {
message("Este mensaje aparece con un 50% de probabilidad.")
}
Si pretendemos ejecutar un bloque de instrucciones, podemos envolverlo entre paréntesis:
x <- 3
if (x < 2) {
y <- 2 * x
z <- 3 * y
}
Recuerda que para que nuestro código sea lo mas legible posible, algunas guías de estilo recomiendan el uso de paréntesis, incluso si sólo queremos ejecutar condicionalmente una sentencia.
El siguiente paso en complejidad en la sintaxis de if
es incluir la cláusula else
. Seguidamente se muestra el diagrama de flujo de if-else
:
El código después de un else
se ejecuta sólo si la condición en if
es FALSE
:
if (FALSE) {
message("Este bloque no se ejecuta...")
} else {
message("pero este si lo hará")
}
## pero este si lo hará
Podemos definir múltiples condiciones combinando if
y else
repetidamente, este tipo de estructura se utiliza para probar condiciones mutuamente excluyentes.
A continuación se muestra el diagrama de flujo de un if-else
anidado. Como podemos observar se puden plantear múltiples condiciones simultáneamente: si se cumple la condición 1 se ejecuta el bloque de intrucciones 1. En caso contrario se comprueba la condición 2; si es cierta se ejecuta el bloque de sentencias 2, y así sucesivamente hasta n condiciones. Si ninguna de ellas se cumple se ejecuta el bloque de instrucciones de else
:
El siguiente ejemplo nos sirve para mostrar el anidamiento de instrucciones if-else
. Pongamos el caso que deseamos crear un algoritmo que nos calcule la medida de tendencia central que deseemos, el siguiente fragmento de código podría ser una posible solución:
## Error in library(modeest): there is no package called 'modeest'
# Creamos una muestra de 20 observaciones del 1 al 100 en el que se pueden
# repetir hasta 2 observaciones
(muestra <- sample(1:100, 20, 2))
## [1] 66 18 32 26 75 23 10 46 15 22 5 42 61 71 71 5 61 73 39 35
## Creamos una variable indicando la medida de tendencia central que queremos
## calcular
centralizacion <- "moda"
## Creamos un algoritmo para calcular la tendencia central que deseemos
if (centralizacion == "moda") {
media = mean(muestra)
message("La media es ", as.character(media))
} else if (centralizacion == "mediana") {
mediana = median(muestra)
message("La mediana es ", as.character(mediana))
} else if (centralizacion == "moda") {
moda = mlv(muestra, method = "mfv")
message("La moda es ", as.character(moda))
} else {
message("Este algoritmo sola calcula la media,
mediana, moda")
}
## La media es 39.8
If
Vectorizado
La instrucción if
estándar acepta en la condición lógica un único valor lógico. Si pasamos un vector lógico con una longitud
mayor que uno, R nos lo indicará mediante un warning indicándonos que hemos introducido múltiples opciones, pero que
únicamente la primera será utilizada:
if (c(TRUE, FALSE)) {
message("dos condiciones")
}
## Warning in if (c(TRUE, FALSE)) {: the condition has length > 1 and only the
## first element will be used
## dos condiciones
Puesto que muchas de las operaciones en R son vectorizadas, R nos proporciona la función ifelse
. La función ifelse
toma tres argumentos. El primer argumento es un vector lógico de condiciones. El segundo es un vector que contiene los valores que
serán devueltos cuando el primer vector es TRUE
. El tercero contiene los valores que serán devueltos cuando el primer vector
es FALSE
.
Uso
str(ifelse)
## function (test, yes, no)
Argumentos
test: un objeto que pueda ser coercionado a un tipo lógico
yes: devuelve los valores `TRUE` en los elementos de `test`
no: devuelve los valores `FALSE` de `test`
En el siguiente ejemplo, la función rbinom
genera
números aleatorios de un distribución binomial simulando el lanzamiento de una moneda:
ifelse(rbinom(n = 10, size = 1, prob = 0.5), "cara", "cruz")
## [1] "cara" "cara" "cara" "cara" "cruz" "cara" "cara" "cruz" "cara" "cara"
No obstante, if(test) yes else no
es mucho mas eficiente y preferible a ifelse(test, yes, no)
cuando test
es decir, la
condición lógica se trata de una expresión cuya longitud sea un vector de longitud igual a 1.
Selección Múltiple con switch()
El código con muchas clausulas else
puede hacer nuestro código difícil de leer. En estas circunstancias, podemos hacer uso de la función switch()
, con la que conseguiremos un código mas legible y fácil de mantener.
Para comprender mejor su funcionamiento pasemos a examinar el diagrama de flujo de la función switch()
:
Esta función permite ejecutar una de entre varias acciones en función del valor de una expresión. Es una alternativa a los if-else
anidados cuando se compara la misma expresión con diferentes valores.
El caso más común toma como primer argumento una expresión que devuelve un string, seguido por varios argumentos con nombre que proporcionan el resultado cuando el nombre coincida con el primer argumento. Cuando se encuentra la primera coincidencia, se ejecuta el bloque de instrucciones y se sale de función. Si no se encuentra ninguna coincidencia con ningún valor, se ejecuta el bloque de sentencias del argumento por defecto.
Uso
str(switch)
## function (EXPR, ...)
Argumentos
EXPR: una expresión que evalua un string
... : una lista con alternativas. Estas alternativas se les dará nombre,
excepto a aquella que sea usada como valor por defecto.
Una alternativa al ejemplo presentado en el apartado anterior mediante la función swith()
es la siguiente:
## Error in library(modeest): there is no package called 'modeest'
# Creamos una muestra de 20 observaciones del 1 al 100 en el que se pueden
# repetir hasta 2 observaciones
(muestra <- sample(1:100, 20, 2))
## [1] 53 93 42 55 33 6 92 14 97 53 63 59 43 97 69 51 29 61 72 55
# Calculamos la media de la muestra
(switch("media", media = mean(muestra), mediana = median(muestra), moda = mlv(muestra,
method = "mfv")))
## [1] 56.85
Si ningún nombre coincide, entonces switch
devuelve NULL
:
# Intentamos calcular la desviación típica
(switch("desviacion_tipica", media = mean(x), mediana = median(x), moda = mlv(x,
method = "mfv")))
## NULL
En este escenario, podemos proporcionar un argumento por defecto sin nombre que switch()
devolverá cuando no coincida ningún otro:
# Intentamos calcular la desviación típica
(switch("desviacion_tipica", media = mean(x), mediana = median(x), moda = mlv(x,
method = "mfv"), "Solo se puede calcular la media, mediana y moda"))
## [1] "Solo se puede calcular la media, mediana y moda"