Uma Lista Guarda Qualquer Coisa
Um vetor tem uma regra rígida: todo elemento precisa ser do mesmo tipo. Uma lista não tem essa regra. Cada elemento de uma lista pode ser de um tipo diferente, de um comprimento diferente, até mesmo outra lista. É o contêiner de uso geral do R:
length() reporta 4 - quatro elementos, mesmo que um deles (scores) contenha três números por si só. Uma lista conta seus compartimentos, não o que está dentro deles. str() (structure) é o jeito mais rápido de ver o que uma lista realmente guarda - uma linha por elemento, com nome, tipo e uma prévia. Faça de str() um reflexo: sempre que uma função lhe entregar algo e você não tiver certeza do que é, dê um str() nele.
Nomes são opcionais (list(1, "a", TRUE) é válido), mas quase sempre valem a pena - uma lista nomeada se documenta sozinha.
As Três Formas de Entrar: [, [[ e $
Essa é a parte das listas que todo mundo erra pelo menos uma vez, então vamos acertar em cheio. Há três operadores de acesso, e eles fazem dois trabalhos diferentes:
[retorna uma lista menor - um contêiner do mesmo tipo, guardando o que você selecionou.[[retorna o próprio elemento - o valor de verdade dentro do compartimento.$é atalho para[[com um nome literal:person$ageéperson[["age"]].
A diferença é invisível quando você imprime casualmente e muito visível no momento em que tenta calcular:
person["scores"] tem classe "list" - uma lista de comprimento 1 com o vetor de notas dentro. person[["scores"]] tem classe "numeric" - o próprio vetor, pronto para mean(). Chame mean() na versão de colchete simples e você recebe um erro dizendo que o argumento não é numérico; essa mensagem de erro é quase sempre um sinal de que você usou [ onde queria [[.
Uma metáfora que gruda: uma lista é um trem. [ te dá um trem mais curto - ainda um trem. [[ abre um vagão e te entrega a carga.
Então quando [ é a ferramenta certa? Quando você quer vários elementos e quer mantê-los empacotados:
Você não pode extrair dois elementos "em si" de uma vez - dois valores precisam de um contêiner - então a seleção de múltiplos elementos é sempre com colchete simples, e sempre resulta em uma lista.
Mais uma diferença: $ usa correspondência parcial (person$sc encontra scores se não for ambíguo), o que é conveniente no console e um risco em scripts. Em código que precisa continuar funcionando, prefira [[ com o nome completo - ele também aceita um nome guardado em uma variável, o que $ não faz.
Adicionar, Alterar, Remover
Listas crescem e encolhem por simples atribuição - nenhum método especial de append é necessário:
- Atribuir a um nome que ainda não existe adiciona o elemento.
- Atribuir a um nome existente o substitui.
- Atribuir à posição
length(x) + 1acrescenta um elemento sem nome. - Atribuir
NULLremove o elemento por completo - a lista fica mais curta. (Esse é o único lugar em queNULLage como um comando de exclusão; se você realmente precisa guardar "nada" em um compartimento, usex["k"] <- list(NULL).)
Para colar duas listas de ponta a ponta, c() funciona em listas assim como em vetores: c(list_a, list_b) retorna uma lista única e mais longa.
Listas Aninhadas
Como um elemento de lista pode ser outra lista, listas se aninham em qualquer profundidade - o que faz delas o formato natural do R para dados estruturados, como JSON parseado ou resultados agrupados:
Navegar para dentro é apenas encadear acessadores - cada $ ou [[ desce um nível. Quando uma estrutura aninhada fica confusa, str(company) mostra a árvore inteira de uma vez, e str(company, max.level = 1) mostra apenas a camada de cima.
Achatando com unlist()
unlist() colapsa uma lista - por mais aninhada que seja - em um único vetor:
Duas coisas a notar. Primeiro, unlist() constrói nomes para você (math1, math2, art) para que você ainda consiga dizer de onde veio cada valor. Segundo - e essa é a armadilha - um vetor guarda apenas um tipo, então dar unlist em uma lista mista força a coerção de tudo para o tipo mais flexível presente. O número 1 voltou como a string "1". Se você der unlist e seus números virarem texto, a lista não era tão uniforme quanto você pensava.
Por Que Listas Importam
Listas podem parecer um assunto de iniciante que você vai superar. É o contrário - elas sustentam a linguagem inteira:
- Funções que retornam várias coisas retornam uma lista. Funções em R retornam um objeto; uma lista faz esse único objeto carregar um valor ajustado aqui, uma tabela de coeficientes ali. Quando você roda uma regressão, o objeto de modelo que volta é uma lista (grande e com classe) - um
str()nele prova isso. - Um data frame é uma lista de colunas - vetores de mesmo comprimento com algum comportamento extra por cima. Tudo o que você acabou de aprender (
$,[[, atribuirNULLpara descartar um elemento) se aplica literalmente às colunas de um data frame. - A família apply -
lapply()e companhia - recebe uma lista, aplica uma função a cada elemento e devolve uma lista. Listas entram, listas saem é o formato padrão de computação repetida no R.
O Que Você Leva Daqui
- Listas guardam qualquer coisa: tipos mistos, comprimentos desiguais, outras listas, data frames inteiros.
[retorna uma lista menor;[[retorna o próprio elemento;$é[[com um nome literal. Vai fazer contas? Você quer[[ou$.- Adicione atribuindo a um nome novo, remova atribuindo
NULL, combine comc(). unlist()achata para um vetor e faz coerção de tipos mistos no caminho - confira a classe do resultado.- Data frames são listas de colunas, então esse conhecimento se transfere diretamente.
A seguir: matrizes - a contraparte de um-só-tipo, com linhas e colunas, da lista.
Perguntas frequentes
Qual é a diferença entre [ e [[ no R?
Colchetes simples [ sempre retornam uma lista contendo os elementos selecionados - um contêiner menor do mesmo tipo. Colchetes duplos [[ alcançam o interior e retornam o próprio elemento. Se x$scores guarda um vetor numérico, x["scores"] é uma lista de comprimento 1 e x[["scores"]] é o vetor numérico. Use [[ (ou $) quando quiser de fato trabalhar com o valor.
Como adicionar um elemento a uma lista no R?
Atribua a um nome que ainda não existe: x$email <- "rosa@example.com" ou x[["email"]] <- .... A lista cresce automaticamente. Para acrescentar sem nome, atribua à próxima posição: x[[length(x) + 1]] <- valor. Para remover um elemento, atribua NULL a ele: x$email <- NULL.
Como converter uma lista em vetor no R?
unlist(x) achata uma lista (inclusive aninhada) em um único vetor. Como um vetor guarda apenas um tipo, tudo sofre coerção para o tipo mais flexível presente - uma lista de números e strings vira um vetor todo de caracteres. Confira a class() do resultado depois do unlist.