Kurzer Hintergrund: Viele (die meisten?) modernen Programmiersprachen, die weit verbreitet sind, haben zumindest eine Handvoll ADTs [abstrakte Datentypen] gemeinsam, vor allem,
-
String (eine Folge von Zeichen)
-
Liste (eine geordnete Sammlung von Werten), und
-
kartenbasierter Typ (ein ungeordnetes Array, das Schlüssel auf Werte abbildet)
In der Programmiersprache R sind die ersten beiden als character
y vector
.
Als ich begann, R zu lernen, waren zwei Dinge fast von Anfang an klar: list
ist der wichtigste Datentyp in R (denn er ist die übergeordnete Klasse für die R data.frame
), und zweitens konnte ich einfach nicht verstehen, wie sie funktionieren, zumindest nicht gut genug, um sie in meinem Code korrekt zu verwenden.
Zum einen schien es mir, dass R's list
Datentyp war eine unkomplizierte Implementierung des map ADT ( dictionary
in Python, NSMutableDictionary
in Objective C, hash
in Perl und Ruby, object literal
in Javascript, und so weiter).
Sie erstellen sie zum Beispiel genauso wie ein Python-Wörterbuch, indem Sie Schlüssel-Wert-Paare an einen Konstruktor übergeben (in Python ist das dict
no list
):
x = list("ev1"=10, "ev2"=15, "rv"="Group 1")
Und Sie greifen auf die Elemente einer R-Liste genauso zu wie auf die eines Python-Wörterbuchs, z. B., x['ev1']
. Ebenso können Sie auch nur die 'Tasten' oder nur die Werte von:
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
aber R list
s sind auch im Gegensatz zu andere map-type ADTs (von den Sprachen, die ich sowieso gelernt habe). Ich vermute, dass dies eine Folge der ursprünglichen Spezifikation für S ist, d.h. der Absicht, eine Daten-/Statistik-DSL [domänenspezifische Sprache] von Grund auf zu entwickeln.
drei signifikante Unterschiede zwischen R list
s und Mapping-Typen in anderen weit verbreiteten Sprachen (z. B. Python, Perl, JavaScript):
erste , list
s in R sind ein bestellt Auflistung, genau wie Vektoren, auch wenn die Werte verschlüsselt sind (d.h. die Schlüssel können beliebige Hash-Werte sein, nicht nur sequentielle Ganzzahlen). Fast immer ist der Mapping-Datentyp in anderen Sprachen ungeordnet .
zweite , list
s können von Funktionen zurückgegeben werden, auch wenn Sie nie eine list
wenn Sie die Funktion aufrufen, und auch wenn die Funktion, die die list
enthält keine (explizite) list
Konstruktor (Natürlich können Sie dies in der Praxis umgehen, indem Sie das zurückgegebene Ergebnis in einen Aufruf von 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
A dritte Besonderheit von R's list
s: es scheint nicht so, dass sie Mitglieder eines anderen ADT sein können, und wenn man das versucht, wird der primäre Container zu einem list
. Z.B.,
x = c(0.5, 0.8, 0.23, list(0.5, 0.2, 0.9), recursive=TRUE)
class(x)
# [1] list
Es ist nicht meine Absicht, die Sprache oder die Art und Weise, wie sie dokumentiert ist, zu kritisieren; auch will ich nicht behaupten, dass etwas an der list
Datenstruktur oder wie sie sich verhält. Alles, was ich will, ist mein Verständnis für ihre Funktionsweise zu korrigieren, damit ich sie in meinem Code korrekt verwenden kann.
Das sind die Dinge, die ich gerne besser verstehen würde:
-
Welche Regeln bestimmen, wann ein Funktionsaufruf eine
list
(z.B.,strsplit
oben zitierten Ausdruck)? -
Wenn ich nicht explizit Namen für eine
list
(z.B.,list(10,20,30,40)
) sind die Standardnamen einfach fortlaufende Ganzzahlen, die mit 1 beginnen? (Ich nehme an, bin mir aber keineswegs sicher, dass die Antwort ja lautet, sonst könnten wir diese Art vonlist
zu einem Vektor mit einem Aufruf vonunlist
.) -
Warum machen diese zwei verschiedene Betreiber,
[]
und[[]]
zurück, die dieselbe Ergebnis?x = list(1, 2, 3, 4)
beide Ausdrücke ergeben "1":
x[1]
x[[1]]
-
warum sind diese beiden Ausdrücke no das gleiche Ergebnis liefern?
x = list(1, 2, 3, 4)
x2 = list(1:4)
Bitte verweisen Sie mich nicht auf die R-Dokumentation ( ?list
, R-intro
) Ich habe ihn sorgfältig gelesen, aber er hilft mir nicht bei der Beantwortung der Fragen, die ich gerade oben zitiert habe.
(Schließlich habe ich vor kurzem von einem R-Paket (verfügbar auf CRAN) namens hash
die Folgendes implementiert konventionell Map-artiges Verhalten über eine S4-Klasse; ich kann dieses Paket durchaus empfehlen).