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