O R tem um conjunto de operadores igual ao de muitas outras linguagens:
1 == 2 # FALSE
1 != 2 # TRUE
1 < 2 # TRUE
1 > 2 # FALSE
1 <= 2 # TRUE
1 >= 2 # FALSE
A forma básica de um if-then-else é:
if (x > 10) {
y <- "big"
} else if (x > 2) {
y <- "medium"
} else {
y <- "tiny"
}
Neste caso, tanto os parênteses ( ) à volta do Boolean como as chavetas { } à volta do corpo são obrigatórios.
Uma condicional if simples pode ser encurtada:
if (x == 0) return("success")
Já a pensar no conceito vector-filtering: a cláusula condicional entre parênteses () tem de dar um único TRUE/FALSE.
Incluir vetores na comparação dá normalmente um vetor de valores Boolean, por isso é preciso envolvê-los numa função de agregação como all() (todos os valores são TRUE?) ou any() (pelo menos um valor é TRUE?).
numbers <- c(4,5,7,9,10,11)
numbers %% 3 == 0 # gives vector of booleans
#> [1] FALSE FALSE FALSE TRUE FALSE FALSE
# use any() to get a single TRUE/FALSE
if (any(numbers %% 3 == 0)) print("1 or more numbers are divisible by 3")
#> [1] "1 or more numbers are divisible by 3"
ifelse
Uma forma alternativa de if-else pode ser útil, desde que haja apenas um resultado verdadeiro/falso.
y <- ifelse(x > 8, "big", "small")
# Don't mix result types:
z <- ifelse(x > 100, 100, "small") # numeric or string result? Expect problems!
O ifelse() recebe exatamente três parâmetros:
TRUE
FALSE.Aceita vetores como entrada e, nesse caso, produz um vetor como saída.
Nesse caso, certifica-te de que ambos os ramos dão origem ao mesmo tipo de dados: numérico, caráter, lógico, etc.
Isto será abordado no conceito vector-functions.
Os dois resultados ("big", "small" no exemplo acima) devem ser valores únicos.
Infelizmente, se deres aqui um vetor mais longo, o R provavelmente fará algo confuso e inesperado, sem emitir qualquer mensagem de aviso.
if_else
Os responsáveis pela linguagem R têm uma política de evitar, tanto quanto possível, alterações que quebrem a compatibilidade. Isto ajuda a manter o enorme número de pacotes de terceiros disponíveis no CRAN, mas limita a capacidade de atualizar o R base com conceitos modernos de programação.
Nos últimos anos, foram lançados vários pacotes que ampliam e, por vezes, substituem funcionalidades do R, com base em décadas de experiência sobre os pontos fortes e fracos do desenho original do R.
Estes pacotes formam a coleção tidyverse.
Foram adicionados ao test runner do Exercism em 2023 e podes usá-los nos exercícios.
O nosso track de R é anterior à adição do tidyverse em vários anos, por isso podes notar que muitas soluções da comunidade se mantêm fiéis à linguagem base.
dplyr
O dplyr serve sobretudo para manipular dataframes (algo que será abordado mais à frente no curso).
Adiciona-o com library(dplyr) no início do teu código, ou com library(tidyverse) para adicionar a coleção completa.
Podes ver mensagens de aviso sobre nomes mascarados, mas raramente isso é um problema.
Para o conceito em questão, vale a pena referir a função if_else.
É em grande parte semelhante a ifelse, no R base.
library(dplyr) # warnings not shown
x <- 10
if_else(x > 8, "big", "small")
#> [1] "big"
A principal diferença é que o if_else pode receber um quarto argumento opcional, para valores em falta que, em R, são representados por NA.
xs <- c(3, NA, 10, NA, 4) # a 5-element vector
xs
#> [1] 3 NA 10 NA 4
if_else(xs > 8, "big", "small", "missing")
#> [1] "small" "missing" "big" "missing" "small"
# contrast:
ifelse(xs > 8, "big", "small")
#> [1] "small" NA "big" NA "small"
Também podes achar que o if_else tem mensagens de erro muito melhores do que o antigo ifelse.
Depois de carregar a biblioteca dplyr, também terás acesso à função between().
O R não permite encadear comparações, por isso 1 <= x <= 5 dará uma mensagem de erro.
Com o dplyr carregado, between(x, 1, 5) é equivalente a x >= 1 & x <= 5 e talvez mais legível.
Tanto o limite inferior como o superior são inclusivos.