3.12 Controle de Fluxo
Como toda boa linguagem de programação, o R possui estruturas de if
, else
, for
e while
. Esses controles de fluxo são muito importantes na hora de programar, pois nos permitem manipular de modo eficiente as ações do computador.
A seguir, explicaremos para que servem e como utilizar cada uma dessas estruturas.
3.12.1 Condicionamento: if e else
As estruturas if
e else
servem para executarmos um código apenas se uma condição (teste lógico) for satisfeita.
No código abaixo, a função Sys.time()
, que retorna a data/hora no momento da execução, só será avaliada se o objeto x
for igual a 1.
# Não vai executar a função Sys.time()
<- 2
x
if (x == 1) {
Sys.time()
}
# Vai executar a função Sys.time()
<- 1
x
if (x == 1) {
Sys.time()
}## [1] "2022-07-12 09:23:00 -03"
O R só vai executar o que está na expressão dentro das chaves {}
se a expressão que estiver dentro dos parênteses ()
retornar TRUE
. Veja outro exemplo:
# Vai fazer a soma
<- c(1, 3, 10, 15)
x
if (class(x) == "numeric") {
sum(x)
}## [1] 29
# Não vai fazer a soma
<- c("a", "b", "c")
x
if (class(x) == "numeric") {
sum(x)
}
Nesse exemplo, a soma só é executada se a classe do objeto x
for numérica, isto é, se x
for um vetor de números. Essa verificação poderia ser colocada dentro de uma função para evitarmos que ela retorne um erro.
<- function(x, y) {
minha_soma if (class(x) == "numeric" & class(y) == "numeric") {
+ y
x
}
}
# Retorna a soma
minha_soma(1, 2)
## [1] 3
# Não retorna nada
minha_soma("a", "b")
Nesses casos, é muito comum o uso das funções return()
e stop()
para, respectivamente, retornar um resultado antecipadamente ou parar a execução da função e devolver uma mensagem de erro personalizada.
Um exemplo usando return()
.
# Devolvendo um resultado antecipadamente
<- function(x, y) {
minha_soma_NA if (class(x) == "numeric" & class(y) == "numeric") {
<- x + y
soma return(soma)
}
NA
}
# Retorna a soma
minha_soma_NA(1, 2)
## [1] 3
# Retorna NA
minha_soma_NA("a", "b")
## [1] NA
# Retorna NA
minha_soma_NA(1, "b")
## [1] NA
Na função minha_soma_NA()
, a soma só é calculada e retornada se x
e y
forem numéricos. Caso pelo menos um dos dois não seja, o código dentro do if
não é executado e o valor retornado é o NA
.
Agora, usando stop()
.
# Agora, devolvendo um erro
<- function(x, y) {
minha_soma_erro if (class(x) != "numeric" | class(y) != "numeric") {
stop("A classe dos objetos x e y deve ser numérica.")
}
+ y
x
}
# Retorna a soma
minha_soma_erro(1, 2)
## [1] 3
# Retorna erro
minha_soma_erro("a", "b")
## Error in minha_soma_erro("a", "b"): A classe dos objetos x e y deve ser numérica.
# Retorna erro
minha_soma_erro(1, "b")
## Error in minha_soma_erro(1, "b"): A classe dos objetos x e y deve ser numérica.
Na função minha_soma_erro()
, testamos no if
se a classe de x
ou a classe de y
é diferente de numeric
, isto é, se pelo menos um dos dois não é um número. Se esse teste retornar TRUE
, a função para a sua execução e devolve a seguinte mensagem de erro: “A classe dos objetos x e y deve ser numérica.”. Se o teste retorna FALSE
, a soma é realizada e seu resultado nos é retornado.
O else
funciona como uma extensão do if
, dando uma alternativa caso o teste executado seja falso.
# Vai fazer a soma
<- c(1, 3, 10, 15)
x
if (class(x) == "numeric") {
sum(x)
else {
} NA
}## [1] 29
# Vai retornar NA
<- c(1, 3, 10, "15")
x
if (class(x) == "numeric") {
sum(x)
else {
} NA
}## [1] NA
Também podemos usar o else
para encadear vários if
s. Teste o código abaixo com valores positivos e negativos para x
.
<- 0
x
if(x < 0) {
"negativo"
else if(x == 0) {
}
"neutro"
else if(x > 0) {
}
"positivo"
}## [1] "neutro"
Repare que o if
no último else
poderia ser omitido.
<- 0
x
if(x < 0) {
"negativo"
else if(x == 0) {
}
"neutro"
else {
}
"positivo"
}## [1] "neutro"
3.12.2 Iteradores: for e while
O for
pode ser utilizado para fazer os famosos loopings de programação, isto é, repetir uma mesma tarefa para um conjunto de valores diferentes. Cada repetição é chamada de iteração e o objeto que muda de valor em cada iteração é chamado de iterador.
<- ncol(mtcars)
numero_de_colunas
for (coluna in 1:numero_de_colunas) {
<- mean(mtcars[,coluna])
media
print(media)
}## [1] 20.09062
## [1] 6.1875
## [1] 230.7219
## [1] 146.6875
## [1] 3.596563
## [1] 3.21725
## [1] 17.84875
## [1] 0.4375
## [1] 0.40625
## [1] 3.6875
## [1] 2.8125
O código acima vai calcular a média de cada coluna do data frame mtcars
. Alguns pontos importantes:
No exemplo, temos 11 iterações e o objeto
coluna
é o iterador.Como
numero_de_colunas
é igual a 11, a expressão1:numero_de_colunas
cria uma sequência de números de 1 a 11.A expressão
coluna in 1:numero_de_colunas
indica que o valor decoluna
será 1 na primeira iteração, 2 na segunda iteração, 3 na terceira e assim por diante.O código dentro do
for
não é retornado para o usuário ao fim de cada iteração. Por isso, para ver os resultados no Console, usamos a funçãoprint()
.
Também podemos salvar as médias em um vetor.
<- ncol(mtcars)
numero_de_colunas
# Antes, criamos um vetor vazio.
<- c()
medias
for (coluna in 1:numero_de_colunas) {
<- mean(mtcars[,coluna])
medias[coluna]
}
medias## [1] 20.090625 6.187500 230.721875 146.687500 3.596563 3.217250
## [7] 17.848750 0.437500 0.406250 3.687500 2.812500
Assim como o for
, o while
também é um iterador.
O código a seguir irá imprimir na tela o valor de i
enquanto este objeto for menor que 3. No momento em que a condição dentro das chaves {}
não for mais respeitada, o processo será interrompido.
<- 1
i
while (i < 3){
print(i)
<- i + 1
i
}## [1] 1
## [1] 2
É importante que o valor de i
seja atualizado em cada interação, caso contrário a função entrará em um loop infinito. Por isso fazemos i <- i + 1
após o print
.
Exercícios
1. Por que o código abaixo retorna erro? Arrume o código para retornar o valor TRUE
.
<- 4
x if(x = 4) {
TRUE
}
2. Usando if
e else
, escreva um código que retorne a string "número"
caso o valor seja da classe numeric
ou integer
; a string "palavra"
caso o valor seja da classe character
; e NA
caso contrário.
3. Usando apenas for
e a função length()
, construa uma função que calcule a média de um vetor número qualquer. Construa uma condição para a função retornar NULL
caso o vetor não seja numérico.
4. Utilize o vetor a
para resolver as questões a seguir:
<- c(10, 3, 5, -1, 3, -4, 8, 9, -10) a
a. Utilize o
for
para imprimir as médias acumuladas do vetora
, isto é, primeiro vamos imprimir 10, depois a média entre 10 e 3, depois a média entre 10, 3 e 5 e assim por diante.b. Adapte o laço que você fez no item anterior para ignorar os valores negativos, isto é, em caso de valor negativo, o laço não deve calcular a média e não imprimir nada.