Os controles de fluxo são operações definidas em todas as linguagens de programação, como por exemplo Python, C, C++, Java, Fortran, Pascal, etc. Como não podia deixar de ser, tais operações também estão definidas dentro da linguagem R.
Cada linguagem de programação tem a sua própria sintaxe, isto é, sua própria regra de como essas operações devem ser usadas. Veremos nessa aula a sintaxe e mais detalhes sobre alguns controles de fluxo para a linguagem R.
Sintaxe:
if (condicao) {
#comandos caso condicao seja verdadeira
} else {
#comandos caso condicao seja falsa
}
ou
if (condicao) {
#comandos caso condicao seja verdadeira
}
Descrição:
Dentro do par de parênteses seguidos do if
tem que ter um objeto do tipo "logical"
. Os comandos dentro do primeiro par de chaves serão executados caso o objeto condicao
seja TRUE
. Caso contrário, os comandos de dentro do par de chaves depois do else
que serão executados. O comando else
é opicional (segundo exemplo de sintaxe). No caso do else
não aparecer, nada será executado caso o objeto condicao
seja FALSE
.
Exemplos:
Vejamos um primeiro exemplo onde um texto é impresso na tela. O que será impresso depende do valor guardado na variável x
. Se x
receber o valor 2, veja qual texto será impresso.
x <- 2
if( x < 5 ){
print(paste(x,"e menor que",5))
} else {
print(paste(x,"e maior ou igual a",5))
}
## [1] "2 e menor que 5"
O comando é responsável por imprimir na tela e o comando por concatenar textos e criar um único objeto do tipo . Para mais detalhes digite no prompt do R e .
Se a variável x
receber um valor maior que 5 o texto impresso é outro.
x <- 7
if( x < 5 ){
print(paste(x,"e menor que",5))
} else {
print(paste(x,"e maior ou igual a",5))
}
## [1] "7 e maior ou igual a 5"
Considere agora um segundo exemplo. De acordo com a seguinte sequência de comandos, qual o valor da variável y
ao final desse código?
x <- 3
if (x > 2){
y <- 2*x
} else {
y <- 3*x
}
Respondeu certo quem disse 6
. O controle de fluxo if/else
será usado na maioria das vezes dentro de funções, como veremos na próxima semana.
Sintaxe:
for(i in valores){
#comandos, que em geral dependem do valor de i
}
Descrição:
Dentro do par de parênteses valores
é um array de objetos, que pode ser de qualquer tipo. Os comandos de dentro do par de chavez serão executados, repetidamente, e em cada iteração o objeto i
vai assumir o valor diferente, valores esses guardados no array valores
.
Exemplos:
Vejamos um primeiro exemplo, bem simples e bem comum.
y<-0
for(i in 1:10){
y<-y+1
}
Ao final do comando qual o valor guardado na variável y
? Antes de responder vamos tentar entender cada passo.
Veja que y
começa com o valor 0
. Quando i=1
, y
é incrementado de 1
unidade e passa a guardar o valor 0+1=1. Quando i=2
, y
é incrementado de mais 1
unidade e passa a guardar o valor 1+1=2. Assim por diante até que temos i=10
, quando y
recebe seu último incremente e passa a guardar o valor 10
.
y
## [1] 10
Vejamos agora um segundo exemplo.
x<-3
for(var in 2:5){
x<-x+var
}
E agora, ao final do comando qual o valor guardado na variável x
? Vamos novamente entender cada passo que está sendo realizado.
Veja que x
começa guardando o valor 3. Na primeira iteração do for
a variável var
assume o valor 2 e dessa forma o valor de x
é atualizado para 3+2=5. Na segunda iteração var
assume o valor 3 e assim o valor de x
é atualizado para 5+3=8. Na iteração seguinte var
assume o valor 4 e x
é atualizado para 8+4=12. Na última iteração var
assume o valor 5 e então o valor de x
recebe a sua última atualização: x = 12+5 = 17. Sendo assim seu valor final igual a 17
.
x
## [1] 17
O exemplo a seguir apresenta valores não numéricos para a variável de dentro do for
. Não é tão comum, mas é possivel de ser feito.
alfabeto = NULL
for(a in LETTERS){
alfabeto = paste(alfabeto,a)
}
alfabeto
## [1] " A B C D E F G H I J K L M N O P Q R S T U V W X Y Z"
Veja que uma pequena mudança no código pode mudar totalmente o resutado final.
alfabeto = NULL
for(a in LETTERS){
alfabeto = paste(a,alfabeto)
}
Qual a diferença entre esse último for e o anterior? Como você acha que ficou o objeto alfabeto
após esse último for
?
alfabeto
## [1] "Z Y X W V U T S R Q P O N M L K J I H G F E D C B A "
Para terminar os exemplos sobre o controle de fluxo for
vamos apresentar alguns exemplos onde dois for
são combinados, um dentro do outro. Suponha que temos uma matriz \(5 \times 5\) cheia de zeros e queremos preencher cada posição dessa matriz com o número 1. O código a seguir executa essa tarefa.
M <- matrix(0,ncol=5,nrow=5)
for(i in 1:5){
for(j in 1:5){
M[i,j] <- 1
}
}
Ao final das linhas de comando descritas acima a matriz M
, que foi iniciada como uma matriz nula, passa a ser uma matriz com todas as posições iguais a 1. Veja que para isso foi preciso usar dois comandos for
, um para controlar o índice das linhas e o outro para controlar o índice das colunas.
Quando um for
é usado dentro do outro é preciso ter o cuidado de usar variáveis diferentes para cada um deles. Para o exemplo acima usamos as variáveis i
para o for
de fora e a variável j
para o for de dentro.
E como ficaria o código se quiséssemos preencher cada posição de uma matriz com o número que indica a sua linha? Por exemplo, a primeira linha da matriz com o número 1, a segunda com o número 2, e assim por diante?
for(i in 1:5){
for(j in 1:5){
M[i,j] <- i
}
}
M
## [,1] [,2] [,3] [,4] [,5]
## [1,] 1 1 1 1 1
## [2,] 2 2 2 2 2
## [3,] 3 3 3 3 3
## [4,] 4 4 4 4 4
## [5,] 5 5 5 5 5
Sintaxe:
while (condicao) {
#comandos
}
Descrição:
Dentro do par de parênteses seguidos do while
tem que ter um objeto do tipo "logical"
. Os comandos dentro do primeiro par de chaves serão executados repetidamente enquanto condicao = TRUE
. É importante garantir que em algum momento teremos condicao = FALSE
, se não o programa não termina de rodar, é o que chamamos de loop infinito.
Exemplos:
A sequência de comandos a seguir usa o controle de fluxo whlie
para criar um vetor com os números de 1 até 100. Veja:
vet <- 1
while(length(vet) < 100){
i <- length(vet)
vet[i+1] <- i+1
}
vet
## [1] 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
## [19] 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
## [37] 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54
## [55] 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72
## [73] 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90
## [91] 91 92 93 94 95 96 97 98 99 100
Veja que o tamanho do vetor cresce em cada iteração do while
, dessa forma sabemos que em algum momento length(vet) < 100
será igual a FALSE
e assim garantimos o fim do programa.
E como podemos usar o while
para criar um vetor com os números pares entre 1 e 100? Veja um alternativa, mas isso poderia ser feito de muitas maneiras diferentes.
vet = NULL
i = 1
while(i < 50){
vet = c(vet,2*i)
i = i + 1
}
vet
## [1] 2 4 6 8 10 12 14 16 18 20 22 24 26 28 30 32 34 36 38 40 42 44 46 48 50
## [26] 52 54 56 58 60 62 64 66 68 70 72 74 76 78 80 82 84 86 88 90 92 94 96 98
Você teria alguma sugestão diferente dessa para criar um array com os números pares menores que 100?
Sintaxe:
repeat{
#comandos
if(condicao)
break
}
Descrição:
Dentro do par de parênteses seguidos do if
tem que ter um objeto do tipo "logical"
. Os comandos dentro do par de parênteses são executados repetidamente até que condicao = TRUE
. É importante garantir que em algum momento teremos condicao = TRUE
, se não o programa não termina de rodar, é o que chamamos de loop infinito.
Este controle de fluxo é muito semelhante ao while
. A diferença é que o while
executa os comandos enquanto uma certa condição for verdadeira, já o repeat
executa os comandos até que uma certa comndição se torne verdadeira.
Na prática o comando break
pode ser aplicado dentro de qualquer controle de fluxo, não apenas no repeat
. Mas ele sempre tem que aparecer no repeat
, pois ele é a forma de garantir o fim das iterações.
Exemplos:
Por exemplo, também podemos usar o repeat/break
para criar um vetor com os 100 primeiros inteiros, veja o código a seguir.
y = 1
i = 1
repeat{
i = i + 1
y[i] = i
if(i==100)
break
}
y
## [1] 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
## [19] 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
## [37] 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54
## [55] 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72
## [73] 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90
## [91] 91 92 93 94 95 96 97 98 99 100
Em geral podemos usar tanto o for
, quanto o while
ou o repeat\break
para implementar o mesmo programa. As vezes um gera um código mais simples que o outro. Não tem um que seja mais fácil, depende muito da tarefa que queremos executar. Vejamos novamente o exemplo que vimos implementado com for
agora com repeat\break
, onde criamos um array com as letras do alfabeto na ordem inversa.
alfabeto = NULL
i = 1
repeat{
a = LETTERS[i]
alfabeto = c(a,alfabeto)
i = i + 1
if(i > length(LETTERS))
break
}
alfabeto
## [1] "Z" "Y" "X" "W" "V" "U" "T" "S" "R" "Q" "P" "O" "N" "M" "L" "K" "J" "I" "H"
## [20] "G" "F" "E" "D" "C" "B" "A"
Quais os valores das variáveis a
e i
ao final desse código? Vamos tentar acompanhar o passo-a-passo feito pelo computador para responder essa pergunta. A resposta é:
a
## [1] "Z"
i
## [1] 27
Para terminar veja um exemplo onde são usados um controle de fluxo dentro do outro. Nele será criada uma lista com 5 posições. Em cada posição i
teremos uma matriz i
\(\times\)i
que guarda na diagonal principal o seu índice dentro da lista.
l = list()
i = 1
while(i <= 5){
D = matrix(0,i,i)
j = 1
repeat{
D[j,j] = i
j = j + 1
if(j > i)
break
}
l[[i]] = D
i = i + 1
}
l
## [[1]]
## [,1]
## [1,] 1
##
## [[2]]
## [,1] [,2]
## [1,] 2 0
## [2,] 0 2
##
## [[3]]
## [,1] [,2] [,3]
## [1,] 3 0 0
## [2,] 0 3 0
## [3,] 0 0 3
##
## [[4]]
## [,1] [,2] [,3] [,4]
## [1,] 4 0 0 0
## [2,] 0 4 0 0
## [3,] 0 0 4 0
## [4,] 0 0 0 4
##
## [[5]]
## [,1] [,2] [,3] [,4] [,5]
## [1,] 5 0 0 0 0
## [2,] 0 5 0 0 0
## [3,] 0 0 5 0 0
## [4,] 0 0 0 5 0
## [5,] 0 0 0 0 5