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.)
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 que obj <- 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"]]
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.