O Laço for Básico
Um laço for em R executa um bloco de código uma vez para cada elemento de um vetor ou lista. A variável do laço assume cada valor por vez:
Três elementos, três passadas. Não há contador para configurar nem condição para manter - for (fruit in fruits) se lê como "para cada fruit em fruits", e é exatamente isso que ele faz. A mesma forma itera sobre os elementos de uma lista, uma sequência de números (for (i in 1:10)) ou os nomes de qualquer coisa via names().
Imprimir Dentro de um Laço Exige print() ou cat()
No console, digitar x imprime seu valor. Dentro do corpo de um laço, não - a impressão automática só acontece no nível superior, e uma expressão solta dentro de um laço é avaliada e jogada fora:
Então quando um laço "não faz nada", esta é a primeira coisa a verificar. Use print() para uma olhada rápida em qualquer valor, ou cat() quando estiver compondo uma linha de saída você mesmo (lembre-se do "\n" - o cat() não adiciona um).
Iterando Sobre Índices com seq_along()
Às vezes você precisa da posição além do valor - para escrever em outro vetor no mesmo índice, ou para imprimir uma lista numerada. Itere sobre índices com seq_along():
Você vai ver for (i in 1:length(prices)) em código mais antigo, e ele abriga um bug genuíno. Quando o vetor está vazio, length() é 0, e 1:0 não significa "nenhuma iteração" - o dois-pontos conta para baixo:
Um laço sobre 1:length(empty) executa duas vezes, indexando elementos que não existem (empty[1] é NA, e atribuições criam entradas fantasmas). seq_along() retorna uma sequência vazia para um vetor vazio, então o corpo do laço simplesmente nunca executa. Faça de seq_along() o hábito; seu irmão seq_len(n) faz o mesmo trabalho quando você tem uma contagem em vez de um vetor.
Coletando Resultados: Pré-aloque, Não Faça Crescer
O primeiro instinto natural para acumular resultados se parece com isto:
squares <- c()
for (i in 1:10000) {
squares <- c(squares, i^2) # copies the ENTIRE vector every pass
}
Funciona, mas cada c(squares, ...) aloca um vetor novinho em folha e copia todos os elementos antigos para dentro dele. Ao final, você copiou cerca de 50 milhões de números para produzir 10.000. Esse antipadrão do vetor que cresce é o maior motivo isolado de as pessoas chamarem os laços do R de lentos.
A correção: crie o resultado no tamanho final primeiro, depois atribua por índice:
Para resultados que não são números, a mesma ideia se aplica com character(n), logical(n) ou vector("list", n) para uma lista de coisas arbitrárias. Laços pré-alocados são perfeitamente rápidos.
next e break
Duas palavras-chave dirigem um laço de dentro do seu corpo: next abandona a passada atual e pula para o próximo elemento; break sai do laço por completo.
Isto imprime 2 4 6 8: valores ímpares são pulados pelo next, e quando o 10 chega, o break encerra o laço antes de imprimir. Use next para filtrar casos cedo (isso mantém o corpo principal sem indentação extra), e break quando um laço encontrou o que procurava e não tem motivo para continuar.
Laços Aninhados
O corpo de um laço pode conter outro laço. O laço interno executa até o fim para cada passada do laço externo - a demonstração clássica é uma tabuada:
Para cada linha i, o laço interno percorre todas as colunas j, e a quebra de linha da linha é impressa depois que o laço interno termina. Laços aninhados vão bem em dois níveis; com três ou mais, o corpo geralmente está pedindo para virar uma função, ou a computação inteira está pedindo para virar um outer() ou uma operação de matriz.
O aninhamento também cobre percorrer uma lista de vetores - laço externo sobre a lista, laço interno (ou melhor, uma chamada vetorizada) sobre cada elemento:
Repare que no fim das contas não há laço interno - mean() cuida do vetor interno inteiro em uma chamada. Essa observação se generaliza, o que nos leva à parte honesta.
Quando Não Usar Laço
R é uma linguagem vetorizada: suas operações básicas já funcionam sobre vetores inteiros de uma vez. Um laço que transforma cada elemento um de cada vez costuma ser um jeito mais longo de escrever uma linha só:
Prefira a forma vetorizada sempre que ela existir - é mais curta, mais difícil de errar e mais rápida. Para aplicar uma função a cada elemento de uma lista, a família apply (sapply, lapply, vapply) cumpre o mesmo papel.
Mas não transforme isso em dogma do tipo "laços são ruins". Um laço é a ferramenta certa quando as iterações dependem das anteriores (estado acumulado, simulações), quando você está produzindo efeitos colaterais como gravar arquivos, ou simplesmente quando o laço é a versão que você e seus leitores entendem de relance. Um laço claro vence uma linha única engenhosa que ninguém consegue decifrar.
O Que Você Leva Daqui
for (x in v) { ... }executa o corpo uma vez por elemento - sem contabilidade de contador.- Dentro de um laço, imprima explicitamente com
print()oucat(); expressões soltas são descartadas. - Itere sobre posições com
seq_along(v), nunca1:length(v)- o segundo executa duas vezes em um vetor vazio. - Pré-aloque resultados com
numeric(n)/vector("list", n)e atribua por índice; crescer comc()copia tudo a cada passada. nextpula uma passada,breaksai; prefira operações vetorizadas quando existirem, mas não tema um laço legível.
A seguir: laços que executam até algo acontecer em vez de uma vez por elemento - while e repeat.
Perguntas frequentes
Como escrever um laço for em R?
for (x in v) { ... } - a variável do laço x assume cada elemento do vetor (ou lista) v por vez, e o corpo executa uma vez por elemento. Para iterar sobre posições em vez de valores, use for (i in seq_along(v)) e indexe com v[i].
Por que usar seq_along em vez de 1:length(v) em R?
Quando v está vazio, length(v) é 0, então 1:length(v) vira 1:0 - o vetor de dois elementos c(1, 0) - e o corpo do laço executa duas vezes sobre elementos que não existem. seq_along(v) retorna uma sequência vazia para um vetor vazio, então o laço corretamente executa zero vezes.
Por que meu laço for em R não imprime nada?
A impressão automática do R só acontece para expressões digitadas no nível superior do console. Dentro do corpo de um laço, uma expressão solta como x é avaliada e descartada. Envolva-a em print(x), ou use cat(...) quando quiser formatar a saída você mesmo.
Laços for são lentos em R?
O laço em si vai bem - o que é lento é fazer um vetor crescer dentro dele com result <- c(result, ...), que copia o vetor inteiro a cada passada. Pré-aloque com numeric(n) ou vector("list", n) e atribua por índice, e o laço tem desempenho perfeitamente bom. Dito isso, quando uma operação vetorizada ou uma chamada da família apply expressa a mesma ideia, ela costuma ser mais rápida e mais clara.