Question La différence entre les notations [] et [[]] pour accéder aux éléments d'une liste ou d'un dataframe


R fournit deux méthodes différentes pour accéder aux éléments d'une liste ou data.frame- le [] et [[]] les opérateurs.

Quelle est la différence entre les deux? Dans quelles situations devrais-je utiliser l'un sur l'autre?


413
2017-07-23 03:33


origine


Réponses:


La définition du langage R est pratique pour répondre à ces types de questions:

R possède trois opérateurs d'indexation de base, avec la syntaxe affichée par les exemples suivants

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

Pour les vecteurs et les matrices, le [[ les formes sont rarement utilisées, bien qu'elles aient de légères différences sémantiques par rapport à la forme (par exemple, elle supprime tout attribut de nom ou de nom de variable, et cette correspondance partielle est utilisée pour les indices de caractères). Lors de l’indexation de structures multidimensionnelles avec un seul index, x[[i]] ou x[i] retournera le il'élément séquentiel de x.

Pour les listes, on utilise généralement [[ pour sélectionner un seul élément, alors que [ renvoie une liste des éléments sélectionnés.

le [[ form ne permet de sélectionner qu'un seul élément à l'aide d'indices entiers ou de caractères, tandis que [ permet l'indexation par des vecteurs. Notez cependant que pour une liste, l'index peut être un vecteur et chaque élément du vecteur est appliqué successivement à la liste, au composant sélectionné, au composant sélectionné de ce composant, et ainsi de suite. Le résultat est toujours un élément unique.


264
2017-07-23 03:46



Les différences significatives entre les deux méthodes sont la classe des objets qu'elles retournent lorsqu'elles sont utilisées pour l'extraction et si elles peuvent accepter une plage de valeurs ou simplement une seule valeur pendant l'affectation.

Prenons le cas de l'extraction de données dans la liste suivante:

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

Disons que nous aimerions extraire la valeur stockée par bool de foo et l'utiliser dans un if() déclaration. Cela illustrera les différences entre les valeurs de retour de [] et [[]] quand ils sont utilisés pour l'extraction de données. le [] la méthode retourne des objets de liste de classes (ou data.frame si foo était un data.frame) alors que le [[]] method renvoie des objets dont la classe est déterminée par le type de leurs valeurs.

Donc, en utilisant le [] méthode aboutit à ce qui suit:

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

class( foo[ 'bool' ] )
[1] "list"

C'est parce que le [] méthode retourné une liste et une liste n'est pas objet valide pour passer directement dans un if() déclaration. Dans ce cas, nous devons utiliser [[]] car il renverra l'objet "nu" stocké dans "bool" qui aura la classe appropriée:

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

class( foo[[ 'bool' ]] )
[1] "logical"

La deuxième différence est que le [] opérateur peut être utilisé pour accéder à un gamme des emplacements dans une liste ou des colonnes dans un bloc de données pendant que le [[]] l'opérateur est limité à l'accès à un unique fente ou colonne. Considérez le cas de l'affectation de valeur en utilisant une deuxième liste, bar():

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

Disons que nous voulons écraser les deux derniers emplacements de foo avec les données contenues dans la barre. Si nous essayons d'utiliser le [[]]opérateur, c'est ce qui se passe:

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

Ceci est dû au fait [[]] se limite à accéder à un seul élément. Nous devons utiliser []:

foo[ 2:3 ] <- bar
print( foo )

$str
[1] "R"

$vec
     [,1] [,2]
[1,]    0    0
[2,]    0    0

$bool
[1] -0.6291121

Notez que bien que l'assignation ait réussi, les slots de foo ont conservé leurs noms d'origine.


145
2017-07-23 03:57



Les doubles crochets accèdent à une liste élément, alors qu'une seule parenthèse vous renvoie une liste avec un seul élément.

lst <- list('one','two','three')

a <- lst[1]
class(a)
## returns "list"

a <- lst[[1]]
class(a)
## returns "character"

89
2017-07-23 03:48



[] extrait une liste, [[]] extrait des éléments de la liste

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"

38
2017-07-23 03:50



Juste en ajoutant ici que [[ est également équipé pour indexation récursive.

Cela a été suggéré dans la réponse de @JijoMatthew mais pas exploré.

Comme indiqué dans ?"[[", syntaxe comme x[[y]], où length(y) > 1, est interprété comme:

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

Notez que ceci ne pas changer ce qui devrait être votre principal à emporter sur la différence entre [ et [[ - à savoir que le premier est utilisé pour sous-ensemble, et ce dernier est utilisé pour extraire éléments de liste unique.

Par exemple,

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

Pour obtenir la valeur 3, nous pouvons faire:

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

Pour en revenir à la réponse de @ JijoMatthew ci-dessus, rappelez-vous r:

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

Cela explique en particulier les erreurs que nous avons tendance à commettre lorsque nous utilisons mal [[, à savoir:

r[[1:3]]

Erreur dans r[[1:3]] : l'indexation récursive a échoué au niveau 2

Puisque ce code a effectivement essayé d'évaluer r[[1]][[2]][[3]], et la nidification de r s'arrête au premier niveau, la tentative d'extraction par indexation récursive a échoué à [[2]], c'est-à-dire au niveau 2.

Erreur dans r[[c("foo", "far")]] : indice hors limites

Ici, R cherchait r[["foo"]][["far"]], ce qui n’existe pas, nous obtenons donc l’erreur en dehors des limites de l’indice.

Ce serait probablement un peu plus utile / cohérent si ces deux erreurs donnaient le même message.


15
2018-04-30 20:29



Les deux sont des moyens de sous-ensembles. Le seul crochet renverra un sous-ensemble de la liste, qui sera en soi une liste. C'est-à-dire: Il peut ou non contenir plus d'un élément. Par contre, un double crochet ne renverra qu'un seul élément de la liste.

-Le support unique nous donnera une liste. Nous pouvons également utiliser un seul crochet si nous souhaitons renvoyer plusieurs éléments de la liste. considérez la liste suivante: -

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

Notez maintenant la manière dont la liste est renvoyée lorsque j'essaie de l'afficher. Je tape r et appuie sur Entrée

>r

#the result is:-

[[1]]

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

$foo

[1] 1

$far

[1] 2

Maintenant, nous verrons la magie du support unique: -

>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

ce qui est exactement le même que lorsque nous avons essayé d'afficher la valeur de r à l'écran, ce qui signifie que l'utilisation d'un seul crochet a renvoyé une liste, où à l'index 1 nous avons un vecteur de 10 éléments. et loin. Nous pouvons également choisir de donner un seul nom d’index ou d’élément en entrée du seul crochet. par exemple:

> r[1]

[[1]]

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

Dans cet exemple, nous avons donné un index "1" et obtenu en retour une liste avec un élément (qui est un tableau de 10 chiffres)

> r[2]

$foo

[1] 1

Dans l'exemple ci-dessus, nous avons donné un index "2" et obtenu en retour une liste avec un élément

> r["foo"];

$foo

[1] 1

Dans cet exemple, nous avons passé le nom d'un élément et, en retour, une liste a été renvoyée avec un élément.

Vous pouvez également passer un vecteur de noms d'éléments comme: -

> x<-c("foo","far")

> r[x];

$foo

[1] 1

$far
[1] 2

Dans cet exemple, nous avons passé un vecteur avec deux noms d'éléments "foo" et "loin"

En retour, nous avons une liste de deux éléments.

En bref, une seule liste vous renvoie toujours une autre liste avec un nombre d'éléments égal au nombre d'éléments ou au nombre d'indices que vous passez dans la parenthèse simple.

En revanche, une double parenthèse retournera toujours un seul élément. Avant de passer au double bracket, notez qu'il faut garder à l'esprit une note. 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.

Je vais citer quelques exemples. Veuillez noter les mots en gras et y revenir après avoir terminé avec les exemples ci-dessous:

Le double crochet vous renverra la valeur réelle à l'index. NE PAS renvoyer une liste)

  > r[[1]]

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


  >r[["foo"]]

    [1] 1

Pour les doubles parenthèses, si nous essayons de voir plus d'un élément en passant un vecteur, cela produira une erreur simplement parce qu'il n'a pas été construit pour répondre à ce besoin, mais simplement pour renvoyer un seul élément.

Considérer ce qui suit

> 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

13
2017-08-30 13:48



De Hadley Wickham:

From Hadley Wickham

Ma modification (à la merde) à afficher en utilisant tidyverse / purrr:

enter image description here


12
2018-04-06 19:38