Menu

If else en R: if, else if, ifelse() y switch()

Lógica condicional en R - sintaxis de if/else if/else, la trampa de las llaves que rompe scripts, ifelse() vectorizado para vectores enteros y switch() para elecciones múltiples.

Esta página incluye editores ejecutables: edita, ejecuta y ve el resultado al instante.

La sentencia if

Una sentencia if en R ejecuta un bloque de código solo cuando una condición es TRUE. La condición va entre paréntesis, el código entre llaves, y un else opcional indica qué ocurre en caso contrario:

La condición score >= 60 se evalúa a un único TRUE, así que se ejecuta la primera rama. Los operadores de comparación y lógicos - ==, >=, &&, %in% y compañía - son con lo que construyes estas condiciones.

Para más de dos desenlaces, encadena comprobaciones con else if. R recorre la cadena desde la primera condición hacia abajo y ejecuta la primera rama cuya condición sea TRUE, saltándose el resto:

El orden importa: como 85 >= 80 se comprueba antes que 85 >= 70, la nota es "B". Si ordenaras las comprobaciones al revés, toda puntuación superior a 70 obtendría una "C".

La trampa de las llaves: dónde debe ir else

Este es el error que le pica a casi todo el mundo en su primer script de R. En un script (o en cualquier cosa ejecutada con Rscript), else debe aparecer en la misma línea que la llave de cierre de la rama anterior. Esto falla:

if (score >= 60) {
  print("You passed")
}
else {              # Error: unexpected 'else'
  print("Try again")
}

Por qué: R analiza sentencia a sentencia. Cuando llega al } al principio de una línea, la sentencia if está sintácticamente completa y R la evalúa ahí mismo. El else de la línea siguiente llega como el comienzo de una nueva sentencia - y una sentencia no puede empezar por else. La solución es el patrón usado a lo largo de esta página:

if (score >= 60) {
  print("You passed")
} else {            # brace and else on the same line
  print("Try again")
}

Dentro del cuerpo de una función o de cualquier conjunto exterior de llaves la regla estricta se relaja (R sigue leyendo hasta que se cierra la llave exterior), pero no dependas de eso - el estilo } else { funciona en todas partes y es lo que prescriben las guías de estilo de R.

La condición debe ser un único TRUE o FALSE

if() exige exactamente un valor lógico. Dos cosas lo incumplen, y ambas son errores:

if (NA) print("hi")
# Error: missing value where TRUE/FALSE needed

if (c(TRUE, FALSE)) print("hi")
# Error: the condition has length > 1

El caso de NA importa en la práctica porque las comparaciones con datos ausentes producen NA: si x es NA, entonces x > 10 es NA, y un if alimentado con esa condición detiene tu script. El patrón defensivo usa el cortocircuito de &&:

Como !is.na(x) es FALSE, la parte x > 10 nunca se evalúa y ningún NA llega a la condición. Cómo se propaga NA a través de las comparaciones se cubre en valores ausentes.

El error de longitud mayor que 1 (impuesto desde R 4.2; antes R usaba en silencio el primer elemento) suele significar que querías decir una de estas cosas: any(v > 5) si basta con una coincidencia, all(v > 5) si todos los elementos deben cumplirlo, o ifelse() si querías una respuesta por elemento - que es la siguiente sección.

ifelse(): if else vectorizado

if decide una vez. ifelse(test, yes, no) decide para cada elemento de un vector y devuelve un vector de la misma longitud:

Cada elemento de temps se evalúa de forma independiente: "hot" "mild" "mild" "hot" "mild". Esta es la herramienta para derivar un nuevo vector o una columna de un data frame a partir de otra existente - sin necesidad de bucles.

A diferencia de if, ifelse() maneja los valores ausentes con elegancia: un NA en la comprobación produce un NA en el resultado en lugar de un error:

Puedes anidar llamadas a ifelse() para divisiones en tres, y a esa profundidad sigue siendo legible:

Pero para ahí. Tres o más llamadas anidadas a ifelse() se convierten en un rompecabezas de emparejar paréntesis; llegado ese punto, recurre a cut() (para rangos numéricos) o a dplyr::case_when(), que pone cada condición en su propia línea.

switch() para elecciones múltiples

Cuando estás comparando un valor contra una lista de nombres conocidos - no comprobando rangos -, una larga cadena de else if es la herramienta torpe. switch() lo dice directamente:

Tres comportamientos que conviene conocer:

  • Coincidencia: switch() compara el valor de tipo carácter con los nombres de los argumentos y devuelve el resultado coincidente.
  • Caída al siguiente caso: un nombre con el lado derecho vacío (sat = ,) cae al resultado del siguiente caso - así es como "sat" y "sun" comparten "weekend" sin repetirlo.
  • Valor por defecto: el último argumento sin nombre ("weekday") se devuelve cuando nada coincide. Sin un valor por defecto, un valor sin coincidencia hace que switch() devuelva NULL de forma invisible - tu función no devuelve nada en silencio, lo que es un bug desconcertante. Proporciona siempre un valor por defecto (o conviértelo en un stop() explícito).

switch() brilla dentro de funciones que despachan según un argumento de modo o método; para cualquier cosa basada en umbrales numéricos, quédate con else if o cut().

Lo que te llevas

  • if (condition) { } else { } - la condición entre paréntesis, se ejecuta una rama; encadena con else if, gana la primera coincidencia.
  • En los scripts, escribe } else { en una sola línea - un else al principio de línea es un error de sintaxis.
  • if() necesita exactamente un TRUE/FALSE: NA es un error, un vector más largo es un error (desde R 4.2). Protégete con !is.na(x) && o reduce con any()/all().
  • ifelse(test, yes, no) es la versión vectorizada - úsala para calcular vectores nuevos y no la anides más de dos veces.
  • switch() maneja el despacho múltiple por nombres, con caída al siguiente caso mediante casos vacíos - dale siempre un valor por defecto.

Lo siguiente: hacer algo más de una vez - los bucles for, y cuándo un bucle es (y no es) la herramienta adecuada.

Preguntas frecuentes

¿Cómo se escribe una sentencia if else en R?

if (condition) { ... } else { ... } - la condición va entre paréntesis y cada rama entre llaves. Encadena más comprobaciones con else if (condition). En un script, else debe ir en la misma línea que la llave de cierre de la rama anterior (} else {), o R informa de unexpected 'else'.

¿Cuál es la diferencia entre if e ifelse() en R?

if es una sentencia de control de flujo que evalúa exactamente un valor TRUE/FALSE y ejecuta una rama de código. ifelse(test, yes, no) es una función vectorizada: evalúa todos los elementos de un vector a la vez y devuelve un vector de resultados. Usa if para decidir qué hace tu programa; usa ifelse() para calcular una nueva columna o vector a partir de otro existente.

¿Por qué R dice 'the condition has length > 1'?

Le pasaste un vector entero a if(), que necesita un único TRUE o FALSE. Desde R 4.2 esto es un error en lugar de un uso silencioso del primer elemento. Arréglalo reduciendo el vector a un solo valor - any(x > 5), all(x > 5) - o pasando al ifelse() vectorizado si querías un resultado por elemento.

¿Cómo funciona switch() en R?

switch(value, name1 = result1, name2 = result2, default) compara un valor de tipo carácter con los nombres de los argumentos y devuelve el resultado que coincide. Un nombre con el lado derecho vacío cae al siguiente resultado, así que varios casos pueden compartir un mismo desenlace. El último argumento sin nombre actúa como valor por defecto; sin él, un valor sin coincidencia devuelve NULL de forma invisible.

Coddy programming languages illustration

Aprende a programar con Coddy

COMENZAR