Bref historique: Beaucoup (la plupart?) De langages de programmation contemporains largement utilisés ont au moins une poignée d'ADT [types de données abstraits] en commun, en particulier,
chaîne (une séquence composée de caractères)
liste (une collection ordonnée de valeurs), et
type basé sur une carte (un tableau non ordonné qui mappe les clés aux valeurs)
Dans le langage de programmation R, les deux premières sont mises en œuvre comme character
et vector
, respectivement.
Quand j'ai commencé à apprendre R, deux choses étaient évidentes presque dès le début: list
est le type de données le plus important dans R (parce que c'est la classe parent pour le R data.frame
), et deuxièmement, je ne pouvais tout simplement pas comprendre comment ils fonctionnaient, au moins pas assez bien pour les utiliser correctement dans mon code.
D'une part, il m'a semblé que le list
type de données de R était une implémentation simple de la carte ADT ( dictionary
en Python, NSMutableDictionary
en Objective C, hash
en Perl et Ruby, object literal
en Javascript, etc.).
Par exemple, vous les créez comme vous le feriez pour un dictionnaire Python, en passant des paires clé-valeur à un constructeur (ce qui n'est dict
pas le cas en Python list
):
x = list("ev1"=10, "ev2"=15, "rv"="Group 1")
Et vous accédez aux éléments d'une liste R comme vous le feriez pour ceux d'un dictionnaire Python, par exemple x['ev1']
. De même, vous pouvez récupérer uniquement les «clés» ou simplement les «valeurs» en:
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
mais les R list
sont également différents des autres ADT de type carte (parmi les langues que j'ai apprises de toute façon). Je suppose que c'est une conséquence de la spécification initiale pour S, c'est-à-dire une intention de concevoir un DSL [langage spécifique au domaine] de données à partir de zéro.
trois différences significatives entre R list
s et les types de mappage dans d'autres langages largement utilisés (par exemple, Python, Perl, JavaScript):
tout d'abord , list
s dans R est une collection ordonnée , tout comme les vecteurs, même si les valeurs sont saisies (c'est-à-dire que les clés peuvent être n'importe quelle valeur lavable et pas seulement des entiers séquentiels). Presque toujours, le type de données de mappage dans d'autres langues n'est pas ordonné .
deuxièmement , list
s peut être renvoyé à partir de fonctions même si vous n'avez jamais passé un list
lorsque vous avez appelé la fonction, et même si la fonction qui a renvoyé le list
ne contient pas de list
constructeur ( explicite) (Bien sûr, vous pouvez gérer cela en pratique en encapsulant le résultat retourné dans un appel à 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
Une troisième caractéristique particulière des R list
: il ne semble pas qu'ils puissent être membres d'un autre ADT, et si vous essayez de le faire, le conteneur principal est contraint à a list
. Par exemple,
x = c(0.5, 0.8, 0.23, list(0.5, 0.2, 0.9), recursive=TRUE)
class(x)
# [1] list
mon intention ici n'est pas de critiquer la langue ou la façon dont elle est documentée; de même, je ne dis pas qu'il y a quelque chose de mal avec la list
structure des données ou comment elle se comporte. Tout ce que je veux, c'est corriger, c'est ma compréhension de leur fonctionnement afin que je puisse les utiliser correctement dans mon code.
Voici le genre de choses que j'aimerais mieux comprendre:
Quelles sont les règles qui déterminent quand un appel de fonction retournera un
list
(par exemple,strsplit
expression récitée ci-dessus)?Si je n'attribue pas explicitement de noms à un
list
(par exemple,list(10,20,30,40)
) les noms par défaut sont-ils uniquement des entiers séquentiels commençant par 1? (Je suppose, mais je suis loin d'être certain que la réponse est oui, sinon nous ne pourrions pas contraindre ce type delist
vecteur à un appel versunlist
.)Pourquoi ces deux opérateurs différents,,
[]
et[[]]
, renvoient-ils le même résultat?x = list(1, 2, 3, 4)
les deux expressions renvoient "1":
x[1]
x[[1]]
pourquoi ces deux expressions ne renvoient-elles pas le même résultat?
x = list(1, 2, 3, 4)
x2 = list(1:4)
Veuillez ne pas me diriger vers la documentation R ( ?list
, R-intro
) - je l'ai lue attentivement et cela ne m'aide pas à répondre au type de questions que j'ai récitées ci-dessus.
(enfin, j'ai récemment appris et commencé à utiliser un package R (disponible sur CRAN) appelé hash
qui implémente un comportement de type carte conventionnel via une classe S4; je peux certainement recommander ce package.)
x = list(1, 2, 3, 4)
, les deux ne renvoient PAS le même résultat:,x[1]
etx[[1]]
. Le premier renvoie une liste et le second renvoie un vecteur numérique. En faisant défiler ci-dessous, il me semble que Dirk était le seul répondant à répondre correctement à cette question.list
dans R, n'est pas comme un hachage. J'en ai un de plus qui, à mon avis, mérite d'être noté.list
dans R peut avoir deux membres avec le même nom de référence. Considérez queobj <- c(list(a=1),list(a=2))
c'est valide et renvoie une liste avec deux valeurs nommées de 'a'. Dans ce cas, un appel àobj["a"]
ne renverra que le premier élément de liste correspondant. Vous pouvez obtenir un comportement similaire (peut-être identique) à un hachage avec un seul élément par nom référencé en utilisant des environnements dans R. Par exemplex <- new.env(); x[["a"]] <- 1; x[["a"]] <- 2; x[["a"]]
Réponses:
Juste pour répondre à la dernière partie de votre question, car cela souligne vraiment la différence entre a
list
etvector
R:Une liste peut contenir n'importe quelle autre classe comme chaque élément. Vous pouvez donc avoir une liste où le premier élément est un vecteur de caractères, le second un bloc de données, etc. Dans ce cas, vous avez créé deux listes différentes.
x
a quatre vecteurs, chacun de longueur 1.x2
a 1 vecteur de longueur 4:Ce sont donc des listes complètement différentes.
Les listes R sont très similaires à une structure de données de carte de hachage en ce que chaque valeur d'index peut être associée à n'importe quel objet. Voici un exemple simple d'une liste qui contient 3 classes différentes (y compris une fonction):
Étant donné que le dernier élément est la fonction de recherche, je peux l'appeler ainsi:
Un dernier commentaire à ce sujet: il convient de noter que a
data.frame
est vraiment une liste (de ladata.frame
documentation):C'est pourquoi les colonnes d'un
data.frame
peuvent avoir différents types de données, contrairement aux colonnes d'une matrice. À titre d'exemple, j'essaie ici de créer une matrice avec des chiffres et des caractères:Notez que je ne peux pas changer le type de données dans la première colonne en numérique car la deuxième colonne a des caractères:
la source
switch
fonction utile dans R qui peut être utilisée à cette fin (voirhelp(switch)
).Concernant vos questions, permettez-moi de les aborder dans l'ordre et de donner quelques exemples:
1 ) Une liste est retournée si et quand la déclaration de retour en ajoute une. Considérer
2 ) Les noms ne sont tout simplement pas définis:
3 ) Ils ne retournent pas la même chose. Votre exemple donne
où
x[1]
renvoie le premier élément dex
- qui est le même quex
. Chaque scalaire est un vecteur de longueur un. Par contrex[[1]]
retourne le premier élément de la liste.4 ) Enfin, les deux sont différents entre eux créent respectivement une liste contenant quatre scalaires et une liste avec un seul élément (qui se trouve être un vecteur de quatre éléments).
la source
Value
. Comme dans?strsplit
: "Une liste de la même longueur que x". Mais vous devez considérer qu'il peut y avoir une fonction qui retourne des valeurs différentes en fonction des arguments (par exemple, sapply peut retourner une liste ou un vecteur).Juste pour prendre un sous-ensemble de vos questions:
Cet article sur l'indexation aborde la question de la différence entre
[]
et[[]]
.En bref, [[]] sélectionne un seul élément dans une liste et
[]
renvoie une liste des éléments sélectionnés. Dans votre exemple, l'x = list(1, 2, 3, 4)'
élément 1 est un entier unique maisx[[1]]
renvoie un seul 1 etx[1]
renvoie une liste avec une seule valeur.la source
A = array( 11:16, c(2,3) ); A[5]
est 15, dans le tableau plat ?!Une des raisons pour lesquelles les listes fonctionnent comme elles le font (ordonnées) est de répondre au besoin d'un conteneur ordonné qui peut contenir n'importe quel type à n'importe quel nœud, ce que les vecteurs ne font pas. Les listes sont réutilisées à diverses fins dans R, y compris la formation de la base de a
data.frame
, qui est une liste de vecteurs de type arbitraire (mais de même longueur).Pourquoi ces deux expressions ne renvoient-elles pas le même résultat?
Pour ajouter à la réponse de @ Shane, si vous souhaitez obtenir le même résultat, essayez:
Ce qui contraint le vecteur
1:4
dans une liste.la source
Juste pour ajouter un point à cela:
R a une structure de données équivalente à la dictée Python dans le
hash
package . Vous pouvez en lire plus dans cet article de blog du groupe Open Data . Voici un exemple simple:En termes de convivialité, la
hash
classe est très similaire à une liste. Mais les performances sont meilleures pour les grands ensembles de données.la source
Vous dites:
Et je suppose que vous suggérez que c'est un problème (?). Je suis ici pour vous dire pourquoi ce n'est pas un problème :-). Votre exemple est un peu simple, en ce sens que lorsque vous effectuez le fractionnement de chaîne, vous avez une liste avec des éléments de 1 élément, vous savez donc que
x[[1]]
c'est la même chose queunlist(x)[1]
. Et si le résultatstrsplit
renvoyait des résultats de longueur différente dans chaque bac. Le simple retour d'un vecteur (par rapport à une liste) ne fera rien du tout.Par exemple:
Dans le premier cas (
x
: qui retourne une liste), vous pouvez dire ce que la 2ème « partie » de la 3ème corde était, par exemple:x[[3]][2]
. Comment pourriez-vous faire de même en utilisantxx
maintenant que les résultats ont été "démêlés" (unlist
-ed)?la source
n'est pas le même parce que 1: 4 est identique à c (1,2,3,4). Si vous voulez qu'ils soient identiques, alors:
la source
Il s'agit d'une question très ancienne, mais je pense qu'une nouvelle réponse pourrait apporter une certaine valeur car, à mon avis, personne n'a directement répondu à certaines des préoccupations du PO.
Malgré ce que suggèrent les réponses acceptées, les
list
objets en R ne sont pas des cartes de hachage. Si vous voulez faire un parallèle avec python, celist
sont plutôt des pythonslist
(ou destuple
s en fait).Il est préférable de décrire comment la plupart des objets R sont stockés en interne (le type C d'un objet R est
SEXP
). Ils sont constitués essentiellement de trois parties:NULL
si l'objet n'a pas d'attributs).D'un point de vue interne, il y a peu de différence entre a
list
et unnumeric
vecteur par exemple. Les valeurs qu'ils stockent sont simplement différentes. Décomposons deux objets dans le paradigme que nous avons décrit précédemment:Pour
x
:numeric
(REALSXP
dans le côté C), la longueur est 10 et d'autres choses.double
valeurs.NULL
, car l'objet n'en a pas.Pour
y
:list
(VECSXP
dans le côté C), la longueur est 2 et d'autres choses.runif(10)
etrunif(3)
respectivement.NULL
, comme pourx
.Donc, la seule différence entre un
numeric
vecteur et unlist
est que lanumeric
partie de données est constituée dedouble
valeurs, tandis que pour lelist
partie de données est un tableau de pointeurs vers d'autres objets R.Que se passe-t-il avec les noms? Eh bien, les noms ne sont que quelques-uns des attributs que vous pouvez attribuer à un objet. Voyons l'objet ci-dessous:
list
(VECSXP
dans le côté C), la longueur est 2 et d'autres choses.1:3
etLETTERS
respectivement.names
composant qui est uncharacter
objet R avec une valeurc("a","b")
.À partir du niveau R, vous pouvez récupérer les attributs d'un objet avec la
attributes
fonction.La valeur-clé typique d'une carte de hachage dans R n'est qu'une illusion. Quand tu dis:
c'est ce qui se passe:
[[
fonction de sous - ensemble est appelée;"a"
) est de typecharacter
, donc la méthode est chargée de rechercher une telle valeur dans l'names
attribut (s'il est présent) de l'objetz
;names
attribut n'est pas là,NULL
est retourné;"a"
valeur y est recherchée. Si"a"
n'est pas un nom de l'objet,NULL
est retourné;z[[1]]
.La recherche par valeur-clé est plutôt indirecte et toujours positionnelle. Aussi, utile de garder à l'esprit:
names
dans R doit être des chaînes (character
vecteurs);dans les cartes de hachage, vous ne pouvez pas avoir deux clés identiques. Dans R, vous pouvez attribuer
names
à un objet avec des valeurs répétées. Par exemple:est parfaitement valide en R. Lorsque vous essayez,
y[["same"]]
la première valeur est récupérée. Vous devez savoir pourquoi à ce stade.En conclusion, la possibilité de donner des attributs arbitraires à un objet vous donne l'apparence de quelque chose de différent d'un point de vue externe. Mais les R
list
ne sont en aucun cas des cartes de hachage.la source
Concernant les vecteurs et le concept de hachage / tableau d'autres langues:
Les vecteurs sont les atomes de R. Par exemple,
rpois(1e4,5)
(5 nombres aléatoires),numeric(55)
(vecteur nul de longueur 55 sur les doubles) etcharacter(12)
(12 chaînes vides), sont tous "de base".Soit des listes, soit des vecteurs
names
.Les vecteurs exigent que tout soit du même type de données. Regarde ça:
Les listes peuvent contenir différents types de données, comme le montrent d'autres réponses et la question du PO lui-même.
J'ai vu des langages (ruby, javascript) dans lesquels les "tableaux" peuvent contenir des types de données variables, mais par exemple en C ++, les "tableaux" doivent être tous du même type de données. Je crois que c'est une question de vitesse / efficacité: si vous en avez un,
numeric(1e6)
vous connaissez sa taille et l'emplacement de chaque élément a priori ; si la chose peut contenir"Flying Purple People Eaters"
dans une tranche inconnue, alors vous devez réellement analyser des choses pour connaître les faits de base à ce sujet.Certaines opérations R standard ont également plus de sens lorsque le type est garanti. Par exemple,
cumsum(1:9)
cela a du sens alorscumsum(list(1,2,3,4,5,'a',6,7,8,9))
que non, sans que le type soit garanti double.Quant à votre deuxième question:
Les fonctions renvoient des types de données différents de ceux qu'ils saisissent tout le temps.
plot
renvoie un tracé même s'il ne prend pas de tracé en entrée.Arg
renvoie unnumeric
même s'il a accepté uncomplex
. Etc.(Et comme pour
strsplit
: le code source est ici .)la source
Bien que cette question soit assez ancienne, je dois dire qu'elle touche exactement les connaissances qui me manquaient lors de mes premiers pas dans R - c'est-à-dire comment exprimer des données dans ma main en tant qu'objet dans R ou comment choisir parmi des objets existants. Il n'est pas facile pour un novice R de penser "dans une boîte R" dès le début.
J'ai donc moi-même commencé à utiliser des béquilles ci-dessous, ce qui m'a beaucoup aidé à découvrir quel objet utiliser pour quelles données, et essentiellement à imaginer une utilisation réelle.
Bien que je ne donne pas de réponses exactes à la question, le court texte ci-dessous pourrait aider le lecteur qui vient de commencer avec R et pose des questions similaires.
[
sous-ensembles.[
sous - ensembles.[
sous ensembles par lignes et colonnes, ou par séquence.list
où je peux sous-ensemble en utilisant des[
lignes et des colonnes, mais même en utilisant[[
.tree structure
laquelle[i]
sélectionne et renvoie des branches entières et[[i]]
renvoie un élément de la branche. Et parce que c'est le castree like structure
, vous pouvez même utiliser unindex sequence
pour adresser chaque feuille sur un très complexe enlist
utilisant son[[index_vector]]
. Les listes peuvent être simples ou très complexes et peuvent mélanger différents types d'objets en un seul.Donc,
lists
vous pouvez vous retrouver avec plus de façons de sélectionner un enleaf
fonction de la situation, comme dans l'exemple suivant.Cette façon de penser m'a beaucoup aidé.
la source
Si cela aide, j'ai tendance à concevoir des "listes" en R comme des "enregistrements" dans d'autres langues pré-OO:
Le nom "record" entrerait en conflit avec la signification standard de "records" (alias lignes) dans le langage de la base de données, et c'est peut-être la raison pour laquelle leur nom se suggère lui-même: sous forme de listes (de champs).
la source
pourquoi ces deux opérateurs différents,,
[ ]
et[[ ]]
, renvoient-ils le même résultat?[ ]
fournit une opération de sous-réglage. En général, le sous-ensemble de tout objet aura le même type que l'objet d'origine. Par conséquent,x[1]
fournit une liste. De mêmex[1:2]
est un sous-ensemble de la liste d'origine, donc c'est une liste. Ex.[[ ]]
sert à extraire un élément de la liste.x[[1]]
est valide et extrayez le premier élément de la liste.x[[1:2]]
n'est pas valide car[[ ]]
ne fournit pas de sous-paramètre comme[ ]
.la source