Respostas:
OR Language Definition é útil para responder a esses tipos de perguntas:
R possui três operadores de indexação básicos, com sintaxe exibida pelos seguintes exemplos
x[i] x[i, j] x[[i]] x[[i, j]] x$a x$"a"
Para vetores e matrizes, os
[[
formulários raramente são usados, embora apresentem pequenas diferenças semânticas do[
formulário (por exemplo, elimina qualquer atributo de nomes ou nomes de nomes e essa correspondência parcial é usada para índices de caracteres). Ao indexar estruturas multidimensionais com um único índice,x[[i]]
oux[i]
retornará oi
th elemento sequencial dex
.Para listas, geralmente se usa
[[
para selecionar qualquer elemento único, 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. Observe que, para uma lista, o índice pode ser um vetor e cada elemento do vetor é aplicado, por sua vez, à lista, ao componente selecionado, ao componente selecionado desse componente e assim por diante. O resultado ainda é um único elemento.
[
sempre retornar um meio de lista que você começa a mesma classe de saída para x[v]
, independentemente da duração da v
. Por exemplo, pode-se querer lapply
mais de um subconjunto de uma lista: lapply(x[v], fun)
. Se você [
soltasse a lista de vetores de comprimento um, isso retornaria um erro sempre que v
tivesse comprimento um.
As diferenças significativas entre os dois métodos são a classe dos objetos que eles retornam quando usados para extração e se eles podem aceitar um intervalo de valores ou apenas um valor único durante a atribuição.
Considere o caso da extração de dados na seguinte lista:
foo <- list( str='R', vec=c(1,2,3), bool=TRUE )
Digamos que gostaríamos de extrair o valor armazenado por bool de foo e usá-lo dentro de uma if()
declaração. Isso ilustrará as diferenças entre os valores de retorno []
e [[]]
quando eles são usados para extração de dados. O []
método retorna objetos da lista de classes (ou data.frame se foo era um data.frame) enquanto o [[]]
método retorna objetos cuja classe é determinada pelo tipo de seus valores.
Portanto, o uso do []
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 objeto válido para passar diretamente para uma if()
instrução. Nesse caso, precisamos usar [[]]
porque ele retornará o objeto "vazio" armazenado em 'bool', que terá a classe 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 substituir os dois últimos slots de foo pelos dados contidos em bar. Se tentarmos usar o [[]]
operador, é isso que acontece:
foo[[ 2:3 ]] <- bar
Error in foo[[2:3]] <- bar :
more elements supplied than there are to replace
Isso ocorre porque o [[]]
acesso a um único elemento é limitado. 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, embora a tarefa tenha sido bem-sucedida, os slots foo mantiveram seus nomes originais.
Os colchetes duplos acessam um elemento da lista , enquanto um colchete fornece 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"
Partida Hadley Wickham:
Minha modificação (de baixa qualidade) para mostrar usando tidyverse / purrr:
[]
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 .
Isso foi sugerido na resposta por @JijoMatthew, mas não explorado.
Conforme observado em ?"[["
, sintaxe como x[[y]]
, onde length(y) > 1
, é interpretada como:
x[[ y[1] ]][[ y[2] ]][[ y[3] ]] ... [[ y[length(y)] ]]
Observe que isso não altera qual deve ser sua principal explicação sobre a diferença entre [
e [[
- ou seja, que o primeiro é usado para subconjunto 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 de @ JijoMatthew acima, lembre-se r
:
r <- list(1:10, foo=1, far=2)
Em particular, isso explica os erros que tendemos a obter ao usar incorretamente [[
, a saber:
r[[1:3]]
Erro em
r[[1:3]]
: falha na indexação recursiva no nível 2
Como esse código realmente tentou avaliar r[[1]][[2]][[3]]
e o aninhamento de r
paradas no nível um, a tentativa de extrair por meio da indexação recursiva falhou [[2]]
no nível 2.
Erro em
r[[c("foo", "far")]]
: subscrito fora dos limites
Aqui, R estava procurando r[["foo"]][["far"]]
, o que não existe, então obtemos o erro de subscrito fora dos limites.
Provavelmente seria um pouco mais útil / consistente se esses dois erros dessem a mesma mensagem.
Ambos são formas de subconjunto. O colchete único retornará um subconjunto da lista, que por si só será uma lista. ou seja: pode ou não conter mais de um elemento. Por outro lado, um colchete retornará apenas um elemento da lista.
-Suporte único nos dará uma lista. Também podemos usar colchetes 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. Digite digito e pressione enter
>r
#the result is:-
[[1]]
[1] 1 2 3 4 5 6 7 8 9 10
$foo
[1] 1
$far
[1] 2
Agora veremos a magia do suporte simples: -
>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 que quando tentamos exibir o valor de r na tela, o que significa que o uso de colchetes retornou uma lista, onde no índice 1 temos um vetor de 10 elementos, temos mais dois elementos com nomes foo e longe. Também podemos optar por fornecer um único índice ou nome de elemento como entrada para o colchete único. por exemplo:
> r[1]
[[1]]
[1] 1 2 3 4 5 6 7 8 9 10
Neste exemplo, fornecemos um índice "1" e, em troca, obtivemos uma lista com um elemento (que é uma matriz de 10 números)
> r[2]
$foo
[1] 1
No exemplo acima, demos um índice "2" e, em troca, obtivemos uma lista com um elemento
> r["foo"];
$foo
[1] 1
Neste exemplo, passamos o nome de um elemento e, em troca, 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, temos uma lista com dois elementos.
Em suma, o colchete único sempre retornará outra lista com número de elementos igual ao número de elementos ou número de índices que você passa para o colchete único.
Por outro lado, um colchete duplo sempre retornará apenas um elemento. Antes de passar para o colchete duplo, observe uma nota.
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.
Vou colocar alguns exemplos. Mantenha uma anotação das palavras em negrito e retorne a ela depois de concluir 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 exibir mais de um elemento passando um vetor, resultará em um erro apenas porque não foi criado 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
[]
retornar uma classe de lista, mesmo que seja um dígito único, é muito pouco intuitivo. Eles deveriam ter criado outra sintaxe, como ([])
para a lista, e [[]]
acessar o elemento real está correto. Prefiro pensar [[]]
no valor bruto como em outros idiomas.
Para ajudar os novatos a navegar pelo nevoeiro manual, pode ser útil ver a [[ ... ]]
notação como uma função em colapso - em outras palavras, é quando você deseja apenas 'obter os dados' de um vetor, lista ou quadro de dados nomeado. É bom fazer isso se você quiser usar dados desses objetos para cálculos. Esses exemplos simples ilustrarão.
(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
iris[[1]]
retorna um vetor, enquanto iris[1]
retorna um data.frame
Sendo terminológico, o [[
operador extrai o elemento de uma lista, enquanto o [
operador pega um subconjunto de uma lista.
Para outro caso de uso concreto, use colchetes duplos quando desejar selecionar um quadro de dados criado pela split()
função. Se você não souber, split()
agrupa um quadro de lista / dados em subconjuntos com base em um campo-chave. É útil se, quando você quiser 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"
Por favor, consulte a explicação detalhada abaixo.
Eu usei o quadro de dados interno no R, chamado mtcars.
> mtcars
mpg cyl disp hp drat wt ...
Mazda RX4 21.0 6 160 110 3.90 2.62 ...
Mazda RX4 Wag 21.0 6 160 110 3.90 2.88 ...
Datsun 710 22.8 4 108 93 3.85 2.32 ...
............
A linha superior da tabela é chamada de cabeçalho que contém os nomes das colunas. Cada linha horizontal posteriormente indica uma linha de dados, que começa com o nome da linha e depois é seguida pelos dados reais. Cada membro de dados de uma linha é chamado de célula.
Para recuperar dados em uma célula, inseriríamos suas coordenadas de linha e coluna no único operador de colchete "[]". As duas coordenadas são separadas por vírgula. Em outras palavras, as coordenadas começam com a posição da linha, seguidas por vírgula e terminam com a posição da coluna. A ordem é importante.
Por exemplo 1: - Aqui está o valor da célula da primeira linha, segunda coluna dos mtcars.
> mtcars[1, 2]
[1] 6
Exemplo 2: - Além disso, podemos usar os nomes de linhas e colunas em vez das coordenadas numéricas.
> mtcars["Mazda RX4", "cyl"]
[1] 6
Fazemos referência a uma coluna de quadro de dados com o operador de colchete duplo "[[]]".
Exemplo 1: - Para recuperar o vetor da nona coluna do conjunto de dados interno mtcars, escrevemos mtcars [[9]].
mtcars [[9]] [1] 1 1 1 0 0 0 0 0 0 0 0 0 ...
Ex. 2: - Podemos recuperar o mesmo vetor de coluna por seu nome.
mtcars [["am"]] [1] 1 1 1 0 0 0 0 0 0 0 0 0 ...