Parte I: Conceitos Básicos de Programação no R

Controle de Fluxo

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.

If/else

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.

for

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

while

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?

repeat/break

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