A diferença entre colchete e colchete duplo ] para acessar os elementos de uma lista ou dataframe

R fornece dois methods diferentes para acessar os elementos de uma lista ou data.frame – os operadores [] e [[]] .

Qual é a diferença entre os dois? Em que situações devo usar uma sobre a outra?

A Definição da Linguagem R é útil para responder a esses tipos de perguntas:

R tem três operadores de indexação básicos, com a syntax exibida pelos exemplos a seguir

     XI]
     x [i, j]
     XI]]
     x [[i, j]]
     x $ a
     x $ "a"

Para vetores e matrizes, as [[ formas raramente são usadas, embora tenham algumas pequenas diferenças semânticas do [formulário (por exemplo, ele descarta qualquer atributo name ou dimnames, e essa correspondência parcial é usada para índices de caracteres). Ao indexar estruturas multidimensionais com um único índice, x[[i]] ou x[i] retornará o iº elemento seqüencial de x .

Para listas, geralmente usa-se [[ para selecionar qualquer elemento individual, enquanto [ retorna uma lista dos elementos selecionados.

O formulário [[ permite que apenas um único elemento seja selecionado usando índices inteiros ou de caracteres, enquanto [ permite a indexação por vetores. No entanto, observe que, para uma lista, o índice pode ser um vetor e cada elemento do vetor é aplicado à lista, ao componente selecionado, ao componente selecionado desse componente e assim por diante. O resultado ainda é um elemento único.

As diferenças significativas entre os dois methods são a class dos objects que eles retornam quando usados ​​para extração e se eles podem aceitar um intervalo de valores, ou apenas um único valor durante a atribuição.

Considere o caso da extração de dados na lista a seguir:

 foo < - list( str='R', vec=c(1,2,3), bool=TRUE ) 

Digamos que gostaríamos de extrair o valor armazenado pelo bool de foo e usá-lo dentro de uma instrução if() . Isso ilustrará as diferenças entre os valores de retorno de [] e [[]] quando forem usados ​​para extração de dados. O método [] retorna objects da lista de classs (ou data.frame, se foo era um data.frame), enquanto o método [[]] retorna objects cuja class é determinada pelo tipo de seus valores.

Portanto, usar o método [] resulta no seguinte:

 if( foo[ 'bool' ] ){ print("Hi!") } Error in if (foo["bool"]) { : argument is not interpretable as logical class( foo[ 'bool' ] ) [1] "list" 

Isso ocorre porque o método [] retornou uma lista e uma lista não é um object válido para passar diretamente para uma instrução if() . Neste caso, precisamos usar [[]] porque ele retornará o object "bare" armazenado em 'bool', que terá a class apropriada:

 if( foo[[ 'bool' ]] ){ print("Hi!") } [1] "Hi!" class( foo[[ 'bool' ]] ) [1] "logical" 

A segunda diferença é que o operador [] pode ser usado para acessar um intervalo de slots em uma lista ou colunas em um quadro de dados, enquanto o operador [[]] está limitado a acessar um único slot ou coluna. Considere o caso da atribuição de valor usando uma segunda lista, bar() :

 bar < - list( mat=matrix(0,nrow=2,ncol=2), rand=rnorm(1) ) 

Digamos que queremos sobrescrever os dois últimos slots de foo com os dados contidos na barra. Se tentarmos usar o operador [[]] , isso é o que acontece:

 foo[[ 2:3 ]] < - bar Error in foo[[2:3]] <- bar : more elements supplied than there are to replace 

Isso ocorre porque [[]] está limitado a acessar um único elemento. Nós precisamos usar [] :

 foo[ 2:3 ] < - bar print( foo ) $str [1] "R" $vec [,1] [,2] [1,] 0 0 [2,] 0 0 $bool [1] -0.6291121 

Observe que enquanto a atribuição foi bem-sucedida, os slots no foo mantiveram seus nomes originais.

Os colchetes duplos acessam um elemento de lista, enquanto um único colchete retorna uma lista com um único elemento.

 lst < - list('one','two','three') a <- lst[1] class(a) ## returns "list" a <- lst[[1]] class(a) ## returns "character" 

[] extrai uma lista, [[]] extrai elementos dentro da lista

 alist < - list(c("a", "b", "c"), c(1,2,3,4), c(8e6, 5.2e9, -9.3e7)) str(alist[[1]]) chr [1:3] "a" "b" "c" str(alist[1]) List of 1 $ : chr [1:3] "a" "b" "c" str(alist[[1]][1]) chr "a" 

Apenas adicionando aqui que [[ também está equipado para indexação recursiva .

Isto foi sugerido na resposta por @JijoMatthew mas não explorado.

Como observado em ?"[[" , Sintaxe como x[[y]] , onde length(y) > 1 , é interpretado como:

 x[[ y[1] ]][[ y[2] ]][[ y[3] ]] ... [[ y[length(y)] ]] 

Note que isso não muda o que deve ser seu principal argumento sobre a diferença entre [ e [[ – ou seja, que o primeiro é usado para subconjuntos , e o último é usado para extrair elementos de lista única.

Por exemplo,

 x < - list(list(list(1), 2), list(list(list(3), 4), 5), 6) x # [[1]] # [[1]][[1]] # [[1]][[1]][[1]] # [1] 1 # # [[1]][[2]] # [1] 2 # # [[2]] # [[2]][[1]] # [[2]][[1]][[1]] # [[2]][[1]][[1]][[1]] # [1] 3 # # [[2]][[1]][[2]] # [1] 4 # # [[2]][[2]] # [1] 5 # # [[3]] # [1] 6 

Para obter o valor 3, podemos fazer:

 x[[c(2, 1, 1, 1)]] # [1] 3 

Voltando à resposta do @JijoMatthew acima, lembre-se de r :

 r < - list(1:10, foo=1, far=2) 

Em particular, isso explica os erros que costumamos ter quando usamos mal [[ , a saber:

 r[[1:3]] 

Erro em r[[1:3]] : a indexação recursiva falhou no nível 2

Como este código realmente tentou avaliar r[[1]][[2]][[3]] , e o aninhamento de r pára no nível um, a tentativa de extrair a indexação recursiva falhou em [[2]] , ie , no nível 2.

Erro em r[[c("foo", "far")]] : subscrito fora dos limites

Aqui, R estava procurando por r[["foo"]][["far"]] , o que não existe, então obtemos o erro subscrito fora dos limites.

Provavelmente seria um pouco mais útil / consistente se ambos os erros dessem a mesma mensagem.

Ambos são formas de subsetting. O único colchete retornará um subconjunto da lista, que por si só será uma lista. ie: Pode ou não conter mais de um elemento. Por outro lado, um colchete duplo retornará apenas um único elemento da lista.

-Single bracket nos dará uma lista. Também podemos usar colchetes individuais se quisermos retornar vários elementos da lista. considere a seguinte lista: –

 >r< -list(c(1:10),foo=1,far=2); 

Agora, observe a maneira como a lista é retornada quando tento exibi-la. Eu digito re pressiono enter

 >r #the result is:- [[1]] [1] 1 2 3 4 5 6 7 8 9 10 $foo [1] 1 $far [1] 2 

Agora vamos ver a magia do colchete único: -

 >r[c(1,2,3)] #the above command will return a list with all three elements of the actual list r as below [[1]] [1] 1 2 3 4 5 6 7 8 9 10 $foo [1] 1 $far [1] 2 

que é exatamente o mesmo de quando tentamos exibir o valor de r na canvas, o que significa que o uso de colchetes retornou uma lista, onde no índice 1 temos um vetor de 10 elementos, então temos mais dois elementos com nomes foo e longe. Também podemos optar por fornecer um único índice ou nome de elemento como input para o único colchete. por exemplo:

 > r[1] [[1]] [1] 1 2 3 4 5 6 7 8 9 10 

Neste exemplo, fornecemos um índice "1" e, em retorno, obtivemos uma lista com um elemento (que é uma matriz de 10 números)

 > r[2] $foo [1] 1 

No exemplo acima nós demos um índice "2" e em troca conseguimos uma lista com um elemento

 > r["foo"]; $foo [1] 1 

Neste exemplo, passamos o nome de um elemento e, em retorno, uma lista foi retornada com um elemento.

Você também pode passar um vetor de nomes de elementos como: -

 > x< -c("foo","far") > r[x]; $foo [1] 1 $far [1] 2 

Neste exemplo, passamos um vetor com dois nomes de elementos "foo" e "far"

Em troca, recebemos uma lista com dois elementos.

Em suma, o colchete único sempre retornará outra lista com um número de elementos igual ao número de elementos ou número de índices que você passa para o colchete único.

Em contraste, um colchete duplo sempre retornará apenas um elemento. Antes de mover para colchete duplo, uma nota deve ser lembrada. NOTE:THE MAJOR DIFFERENCE BETWEEN THE TWO IS THAT SINGLE BRACKET RETURNS YOU A LIST WITH AS MANY ELEMENTS AS YOU WISH WHILE A DOUBLE BRACKET WILL NEVER RETURN A LIST. RATHER A DOUBLE BRACKET WILL RETURN ONLY A SINGLE ELEMENT FROM THE LIST.

Eu localizarei alguns exemplos. Por favor, mantenha uma nota das palavras em negrito e volte a ela depois de terminar com os exemplos abaixo:

O colchete duplo retornará o valor real no índice ( NÃO retornará uma lista)

  > r[[1]] [1] 1 2 3 4 5 6 7 8 9 10 >r[["foo"]] [1] 1 

para colchetes duplos, se tentarmos visualizar mais de um elemento passando um vetor, ele resultará em um erro apenas porque ele não foi construído para atender a essa necessidade, mas apenas para retornar um único elemento.

Considere o seguinte

 > r[[c(1:3)]] Error in r[[c(1:3)]] : recursive indexing failed at level 2 > r[[c(1,2,3)]] Error in r[[c(1, 2, 3)]] : recursive indexing failed at level 2 > r[[c("foo","far")]] Error in r[[c("foo", "far")]] : subscript out of bounds 

Para ajudar os novatos a navegar pela neblina manual, pode ser útil ver a notação [[ ... ]] como uma function de recolhimento – em outras palavras, é quando você quer apenas ‘obter os dados’ de um vetor nomeado, lista ou quadro de dados. É bom fazer isso se você quiser usar dados desses objects para cálculos. Esses exemplos simples serão ilustrados.

 (x < - c(x=1, y=2)); x[1]; x[[1]] (x <- list(x=1, y=2, z=3)); x[1]; x[[1]] (x <- data.frame(x=1, y=2, z=3)); x[1]; x[[1]] 

Então, a partir do terceiro exemplo:

 > 2 * x[1] x 1 2 > 2 * x[[1]] [1] 2 

De Hadley Wickham:

De Hadley Wickham

Minha (porcaria procurando) modificação para mostrar usando tidyverse / purrr:

insira a descrição da imagem aqui

Para mais um caso de uso concreto, use colchetes duplos quando quiser selecionar um quadro de dados criado pela function split() . Se você não sabe, o split() agrupa uma lista / quadro de dados em subconjuntos com base em um campo-chave. É útil quando você deseja operar em vários grupos, plotá-los etc.

 > class(data) [1] "data.frame" > dsplit< -split(data, data$id) > class(dsplit) [1] "list" > class(dsplit['ID-1']) [1] "list" > class(dsplit[['ID-1']]) [1] "data.frame" 

Sendo terminológico, [[ operador extrai o elemento de uma lista enquanto [ operador recebe um subconjunto de uma lista.