Um vector (tecnicamente um atomic vector) em R é uma coleção de valores do mesmo type: habitualmente integer, numeric, character, logical; raramente complex ou raw.
São armazenados de forma contígua em memória, à semelhança de um array em C.
Se receber entradas mistas, o R converte-as silenciosamente para um tipo comum, habitualmente character, o que pode dar origem a resultados inesperados.
v <- c(2, 5.4, "txt")
v
#> [1] "2" "5.4" "txt"
typeof(v)
#> [1] "character"
Se já tens todos os valores, usa c() (abreviatura de «concatenar»):
x <- 10
v <- c(4, 7, x)
A função c() é muito flexível e as entradas podem incluir outros vetores e intervalos.
A função c() aceita qualquer número e variedade de entradas e aplana-as num único vetor.
Se o vetor começa pequeno e cresce muito durante a execução (por exemplo, ao adicionar valores num ciclo), pode ser bastante mais rápido pré-alocar um vetor longo que poderá ser preenchido com dados reais mais tarde:
v <- vector(length = 100)
Isto minimiza a necessidade de copiar o objeto: uma operação lenta e que consome muita memória para vetores longos.
Para um intervalo de valores consecutivos (crescentes ou decrescentes) podes usar a notação :
v <- 1:5 # equivalent to c(1, 2, 3, 4, 5)
w <- 10:7 # c(10, 9, 8, 7)
Em R, os intervalos não são um tipo à parte: são apenas uma forma abreviada de construir um vetor.
A função seq() oferece um controlo mais fino:
# specify step size
seq(2, 11, by = 3) # c(2, 5, 8, 11)
# specify number of values, evenly-spaced
seq(2.5, 4, length.out = 5) # c(2.500, 2.875, 3.250, 3.625, 4.000)
A função rep() facilita a criação de padrões repetidos:
count <- 3
rep(7, count)
#> [1] 7 7 7
rep(1:3, count)
#> [1] 1 2 3 1 2 3 1 2 3
rep(1:3, each = 2) # the "each" keyword is required in this case
#> [1] 1 1 2 2 3 3
Alguns intervalos estão pré-definidos como constantes internas:
letters # LETTERS is the UPPERCASE equivalent
#> [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"
month.name
#> [1] "January" "February" "March" "April" "May" "June" "July" "August"
#> [9] "September" "October" "November" "December"
month.abb
#> [1] "Jan" "Feb" "Mar" "Apr" "May" "Jun" "Jul" "Aug" "Sep" "Oct" "Nov" "Dec"
As operações são aplicadas automaticamente elemento a elemento ao longo do vetor. Os ciclos, as compreensões de listas e as recursões comuns noutras linguagens não são necessários e, por razões de desempenho, devem ser evitados sempre que possível.
2 + 1:3 # c(3, 4, 5)
2 * 1:3 # c(2, 4, 6)
12 / 1:3 # c(12 6 4)
2 ^ (1:3) # c(2, 4, 8) : exponentiation, operator precedence order here needs ()
Os pares de vetores também funcionam, com os elementos tratados aos pares:
v <- 1:3
w <- 5:7
v + w
#> [1] 6 8 10
v * w
#> [1] 5 12 21
v ^ w
#> [1] 1 64 2187
Isto é mais poderoso do que parece à primeira vista, e haverá mais para explorar em conceitos posteriores.
Tal como em muitas linguagens, podemos usar o índice entre parênteses retos:
v <- 4:7
v[2]
#> [1] 5
v[2:4]
#> [1] 5 6 7
Mas atenção: o R usa indexação com base em 1 por predefinição. Isto é comum em linguagens científicas (Fortran, Matlab, Julia), mas difere da indexação com base em zero do C e de muitos dos seus sucessores.
Podem usar-se intervalos, como no exemplo acima, mas também na muito flexível função c():
v <- c(4, 7, 10)
w <- c(2, v[2:3], 11) # c(2, 7, 10, 11)
Os vectors (como a maioria das coisas em R) podem ser tratados como mutáveis, usando uma sintaxe flexível semelhante para escrever num ou em vários elementos:
v <- 1:10
v[2] <- 42
v[4:6] <- c(11, 12, 13)
v
#> [1] 1 42 3 11 12 13 7 8 9 10
Quem programa noutras linguagens pode pensar que v[-1] é uma forma de aceder ao último elemento de um vetor.
Errado!
Para isso, usa tail().
v <- c(2, 4, 6) # defaults to last 6 entries
tail(v)
#> [1] 2 4 6
tail(v, n=1) # just the last entry
#> [1] 6
Os índices negativos são, na verdade, uma forma de remover um elemento:
v <- c(2, 4, 6)
v[-2]
#> [1] 2 6 # second element gone
Isto devolve uma cópia mais curta do vetor. O próprio v não é alterado.
Aplicar comparações a um vetor devolve um vetor de Boolean com o mesmo comprimento.
Isto pode ser muito prático dentro de funções como all() e any():
v <- c(4, 7, 10)
v >= 6
#> [1] FALSE TRUE TRUE
all(v > 6)
#> [1] FALSE # not all elements match this condition
any(v > 6)
#> [1] TRUE # at least one element matches
Para expressões lógicas mais complicadas, é importante usar os operadores & e |, que funcionam com vetores.
Os operadores de dois caracteres && e || destinam-se apenas a comparar valores únicos, como se explica no [conceito de Boolean][concept-boolean].
v <- c(4, 7, 10)
v %% 2 == 0 & v > 5
#> [1] FALSE FALSE TRUE
Este será um tema a retomar em tópicos posteriores. Por agora, repara apenas no formato da saída na consola:
1:20
#> [1] 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
#> [18] 18 19 20
As linhas começam com números entre [ ] para indicar o índice do primeiro elemento (útil para vetores longos que ocupam várias linhas).
Mas porque é que os valores únicos são precedidos de [1]?
Não existem valores verdadeiramente escalares em R!
O que parece ser um único número ou letra é, na verdade, um vetor de comprimento 1.
Já vimos indícios disto nos conceitos Noções básicas e Boolean, com os tipos numérico e lógico.
Os vetores descritos acima são mais formalmente conhecidos como atomic vectors. Isto acontece porque só podem conter valores simples e indivisíveis (daí «atomic») como numeric, character, boolean. Estruturas mais complexas podem formar recursive vectors, que serão apresentados quando abordarmos as lists.