Kurzer Hintergrund: Viele (die meisten?) Zeitgenössische Programmiersprachen, die weit verbreitet sind, haben mindestens eine Handvoll ADTs (abstrakte Datentypen) gemeinsam, insbesondere
Zeichenfolge (eine Folge von Zeichen)
Liste (eine geordnete Sammlung von Werten) und
Kartenbasierter Typ (ein ungeordnetes Array, das Schlüssel Werten zuordnet)
In der Programmiersprache R sind die ersten beiden als character
und implementiertvector
.
Als ich anfing, R zu lernen, waren fast von Anfang an zwei Dinge offensichtlich: list
ist der wichtigste Datentyp in R (weil es die übergeordnete Klasse für das R istdata.frame
), und zweitens konnte ich zumindest nicht verstehen, wie sie funktionierten nicht gut genug, um sie in meinem Code richtig zu verwenden.
Zum einen schien mir der list
Datentyp von R eine einfache Implementierung der Map ADT zu sein ( dictionary
in Python, NSMutableDictionary
in Objective C, hash
in Perl und Ruby,object literal
in Javascript usw.).
Sie erstellen sie beispielsweise wie ein Python-Wörterbuch, indem Sie Schlüssel-Wert-Paare an einen Konstruktor übergeben (was in Python dict
nicht der Fall ist list
):
x = list("ev1"=10, "ev2"=15, "rv"="Group 1")
Und Sie greifen auf die Elemente einer R-Liste zu, genau wie auf die eines Python-Wörterbuchs, z x['ev1']
. Ebenso können Sie nur die 'Schlüssel' oder nur die 'Werte' abrufen , indem Sie:
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 anders als andere ADTs vom Kartentyp (unter den Sprachen, die ich sowieso gelernt habe). Ich vermute, dass dies eine Folge der ursprünglichen Spezifikation für S ist, dh die Absicht, eine Daten- / Statistik-DSL [domänenspezifische Sprache] von Grund auf zu entwerfen.
Drei signifikante Unterschiede zwischen list
Rs und Mapping-Typen in anderen weit verbreiteten Sprachen (z. B. Python, Perl, JavaScript):
Erstens sind list
s in R eine geordnete Sammlung, genau wie Vektoren, obwohl die Werte verschlüsselt sind (dh 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
kann s von Funktionen zurückgegeben werden , obwohl Sie nie in einem übergeben , list
wenn Sie die Funktion aufgerufen, und auch wenn die Funktion , die zurückgegeben die list
keinen (expliziten) enthalten list
Konstruktor (Natürlich können Sie mit diesem in der Praxis beschäftigen , indem Umschließen des zurückgegebenen Ergebnisses 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
Eine dritte Besonderheit von list
Rs: Es scheint nicht, dass sie Mitglieder eines anderen ADT sein können, und wenn Sie dies versuchen, wird der primäre Container zu a gezwungen list
. Z.B,
x = c(0.5, 0.8, 0.23, list(0.5, 0.2, 0.9), recursive=TRUE)
class(x)
# [1] list
Ich habe hier nicht die Absicht, die Sprache oder deren Dokumentation zu kritisieren. Ebenso schlage ich nicht vor, dass irgendetwas mit dem nicht stimmtlist
Datenstruktur oder ihrem Verhalten . Ich muss nur korrigieren, wie sie funktionieren, damit ich sie in meinem Code richtig verwenden kann.
Hier sind die Dinge, die ich besser verstehen möchte:
Welche Regeln bestimmen, wann ein Funktionsaufruf ein
list
(z. B. denstrsplit
oben angegebenen Ausdruck) zurückgibt?Wenn ich a
list
(z. B.list(10,20,30,40)
) nicht explizit Namen zuweise, sind die Standardnamen nur sequentielle Ganzzahlen, die mit 1 beginnen? (Ich nehme an, aber ich bin weit davon entfernt, sicher zu sein, dass die Antwort ja lautet, sonst könnten wir diese Art von nichtlist
zu einem Vektor mit einem Aufruf von zwingenunlist
.)Warum geben diese beiden unterschiedlichen Operatoren
[]
und[[]]
das gleiche Ergebnis zurück?x = list(1, 2, 3, 4)
beide Ausdrücke geben "1" zurück:
x[1]
x[[1]]
Warum geben diese beiden Ausdrücke nicht dasselbe Ergebnis zurück?
x = list(1, 2, 3, 4)
x2 = list(1:4)
Bitte verweisen Sie mich nicht auf die R-Dokumentation ( ?list
, R-intro
) - ich habe sie sorgfältig gelesen und sie hilft mir nicht bei der Beantwortung der oben genannten Fragen.
(Zuletzt habe ich kürzlich von einem R-Paket (verfügbar auf CRAN) erfahren, hash
das herkömmliches Verhalten vom Kartentyp über eine S4-Klasse implementiert . Ich kann dieses Paket auf jeden Fall empfehlen.)
list
in R nicht wie ein Hash sind. Ich habe noch eine, die ich für bemerkenswert halte. list
in R können zwei Mitglieder mit demselben Referenznamen sein. Betrachten Sie dies obj <- c(list(a=1),list(a=2))
als gültig und geben Sie eine Liste mit zwei benannten Werten von 'a' zurück. In diesem Fall gibt ein Aufruf von obj["a"]
nur das erste übereinstimmende Listenelement zurück. Sie können ein ähnliches (möglicherweise identisches) Verhalten wie ein Hash mit nur einem Element pro referenziertem Namen in Umgebungen in R x <- new.env(); x[["a"]] <- 1; x[["a"]] <- 2; x[["a"]]
x = list(1, 2, 3, 4)
beide NICHT das gleiche Ergebnis zurück:,x[1]
undx[[1]]
. Der erste gibt eine Liste zurück und der zweite gibt einen numerischen Vektor zurück. Wenn ich unten scrolle, scheint mir Dirk der einzige Befragte zu sein, der diese Frage richtig beantwortet hat.