Breve histórico: Muitas (mais?) Linguagens de programação contemporâneas de uso amplo têm pelo menos um punhado de ADTs [tipos de dados abstratos] em comum, em particular,
string (uma sequência composta de caracteres)
lista (uma coleção ordenada de valores) e
tipo baseado em mapa (uma matriz não ordenada que mapeia chaves para valores)
Na linguagem de programação R, os dois primeiros são implementados como character
e vector
, respectivamente.
Quando comecei a aprender R, duas coisas eram óbvias quase desde o início: list
é o tipo de dados mais importante em R (porque é a classe pai para o R data.frame
) e, segundo, eu simplesmente não conseguia entender como eles funcionavam, pelo menos não é bom o suficiente para usá-los corretamente no meu código.
Por um lado, pareceu-me que o list
tipo de dados de R era uma implementação direta do mapa ADT ( dictionary
em Python, NSMutableDictionary
em Objective C, hash
em Perl e Ruby, object literal
em Javascript e assim por diante).
Por exemplo, você os cria da mesma forma que faria com um dicionário Python, passando pares de valores-chave para um construtor (o que em Python dict
não é list
):
x = list("ev1"=10, "ev2"=15, "rv"="Group 1")
E você acessa os itens de uma lista R exatamente como faria em um dicionário Python, por exemplo x['ev1']
,. Da mesma forma, você pode recuperar apenas as 'chaves' ou apenas os 'valores' :
names(x) # fetch just the 'keys' of an R list
# [1] "ev1" "ev2" "rv"
unlist(x) # fetch just the 'values' of an R list
# ev1 ev2 rv
# "10" "15" "Group 1"
x = list("a"=6, "b"=9, "c"=3)
sum(unlist(x))
# [1] 18
mas Rs list
também são diferentes de outros ADTs do tipo mapa (dentre os idiomas que aprendi de qualquer maneira). Meu palpite é que isso é uma consequência da especificação inicial para S, ou seja, uma intenção de projetar uma DSL de dados / estatísticas [idioma específico do domínio] a partir do zero.
três diferenças significativas entre Rs list
e tipos de mapeamento em outros idiomas em uso generalizado (por exemplo, Python, Perl, JavaScript):
primeiro , list
s em R são uma coleção ordenada , assim como vetores, mesmo que os valores sejam digitados (ou seja, as chaves podem ser qualquer valor que possa ser lavável e não apenas números inteiros seqüenciais). Quase sempre, o tipo de dados de mapeamento em outros idiomas não é ordenado .
segundo , list
s podem ser retornados de funções, mesmo que você nunca tenha passado um list
quando você chamou a função, e mesmo que a função que retornou list
não contenha um list
construtor ( explícito) (é claro, você pode lidar com isso na prática, agrupando o resultado retornado em uma chamada para unlist
):
x = strsplit(LETTERS[1:10], "") # passing in an object of type 'character'
class(x) # returns 'list', not a vector of length 2
# [1] list
Uma terceira característica peculiar de R's list
: não parece que eles possam ser membros de outro ADT e, se você tentar fazer isso, o contêiner primário será coagido a a list
. Por exemplo,
x = c(0.5, 0.8, 0.23, list(0.5, 0.2, 0.9), recursive=TRUE)
class(x)
# [1] list
minha intenção aqui não é criticar a linguagem ou como ela é documentada; Da mesma forma, não estou sugerindo que haja algo errado com a list
estrutura de dados ou como ela se comporta. Tudo o que eu preciso é corrigir o meu entendimento de como eles funcionam, para que eu possa usá-los corretamente no meu código.
Aqui estão os tipos de coisas que eu gostaria de entender melhor:
Quais são as regras que determinam quando uma chamada de função retornará uma
list
(por exemplo,strsplit
expressão recitada acima)?Se eu não atribuir explicitamente nomes a
list
(por exemplo,list(10,20,30,40)
) , os nomes padrão são apenas números inteiros sequenciais começando com 1? (Presumo, mas estou longe de ter certeza de que a resposta é sim, caso contrário não poderíamos coagir esse tipo delist
vetor a uma chamada paraunlist
.)Por que esses dois operadores diferentes,,
[]
e[[]]
retornam o mesmo resultado?x = list(1, 2, 3, 4)
ambas as expressões retornam "1":
x[1]
x[[1]]
por que essas duas expressões não retornam o mesmo resultado?
x = list(1, 2, 3, 4)
x2 = list(1:4)
Por favor, não me aponte para a Documentação R ( ?list
, R-intro
) - Li-a com atenção e não me ajuda a responder ao tipo de perguntas que recitei logo acima.
(por último, eu aprendi recentemente e comecei a usar um pacote R (disponível no CRAN) chamado hash
que implementa o comportamento do tipo de mapa convencional por meio de uma classe S4; certamente posso recomendar este pacote.)
list
em R não é como um hash. Tenho mais uma que acho digna de nota. list
em R pode ter dois membros com o mesmo nome de referência. Considere que obj <- c(list(a=1),list(a=2))
é válido e retorna uma lista com dois valores nomeados de 'a'. Nesse caso, uma chamada obj["a"]
retornará apenas o primeiro elemento da lista correspondente. Você pode obter um comportamento semelhante (talvez idêntico) a um hash com apenas um item por nomes referenciados usando ambientes em R. por exemplox <- new.env(); x[["a"]] <- 1; x[["a"]] <- 2; x[["a"]]
x = list(1, 2, 3, 4)
, ambos NÃO retornam o mesmo resultado:,x[1]
ex[[1]]
. O primeiro retorna uma lista e o segundo retorna um vetor numérico. Rolando abaixo, parece-me que Dirk foi o único entrevistado a responder corretamente a essa pergunta.