Eine Liste hält alles
Ein Vektor hat eine harte Regel: Jedes Element muss denselben Typ haben. Eine Liste hat diese Regel nicht. Jedes Element einer Liste darf einen anderen Typ, eine andere Länge, sogar eine weitere Liste sein. Sie ist R's Allzweckcontainer:
length() meldet 4 - vier Elemente, obwohl eines davon (scores) selbst drei Zahlen enthält. Eine Liste zählt ihre Fächer, nicht was darin liegt. str() (structure) ist der schnellste Weg zu sehen, was eine Liste tatsächlich enthält - eine Zeile pro Element mit Name, Typ und Vorschau. Mach str() zum Reflex: Wann immer dir eine Funktion etwas zurückgibt und du nicht sicher bist, was es ist, str() es.
Namen sind optional (list(1, "a", TRUE) ist zulässig), aber fast immer lohnend - eine benannte Liste dokumentiert sich selbst.
Die drei Wege hinein: [, [[ und $
Das ist der Teil der Listen, den jeder einmal falsch macht, also machen wir ihn genau richtig. Es gibt drei Zugriffsoperatoren, und sie erledigen zwei verschiedene Aufgaben:
[gibt eine kleinere Liste zurück - einen Container derselben Art mit dem, was du ausgewählt hast.[[gibt das Element selbst zurück - den tatsächlichen Wert im Fach.$ist Kurzschrift für[[mit einem wörtlichen Namen:person$ageistperson[["age"]].
Der Unterschied ist unsichtbar, wenn du beiläufig ausgibst, und sehr sichtbar in dem Moment, in dem du rechnen willst:
person["scores"] hat die Klasse "list" - eine Liste der Länge 1 mit dem scores-Vektor darin. person[["scores"]] hat die Klasse "numeric" - der Vektor selbst, bereit für mean(). Rufst du mean() auf der einfachen Klammervariante auf, bekommst du einen Fehler, dass das Argument nicht numerisch sei; diese Fehlermeldung ist fast immer ein Zeichen, dass du [ benutzt hast, wo du [[ meintest.
Eine Metapher, die haften bleibt: Eine Liste ist ein Zug. [ gibt dir einen kürzeren Zug - immer noch ein Zug. [[ öffnet einen Waggon und reicht dir die Fracht.
Wann ist [ also das richtige Werkzeug? Wenn du mehrere Elemente willst und sie verpackt behalten möchtest:
Du kannst nicht zwei Elemente "selbst" auf einmal herausziehen - zwei Werte brauchen einen Container -, also ist Mehrfachauswahl immer einfache Klammer und ergibt immer eine Liste.
Noch ein Unterschied: $ nutzt partielles Abgleichen (person$sc findet scores, wenn es eindeutig ist), was in der Konsole bequem und in Skripten ein Risiko ist. In Code, der weiterhin funktionieren muss, bevorzuge [[ mit dem vollen Namen - es akzeptiert außerdem einen in einer Variablen gespeicherten Namen, was $ nicht kann.
Hinzufügen, Ändern, Entfernen
Listen wachsen und schrumpfen durch schlichte Zuweisung - keine spezielle Append-Methode nötig:
- Die Zuweisung an einen noch nicht existierenden Namen fügt das Element hinzu.
- Die Zuweisung an einen existierenden Namen ersetzt ihn.
- Die Zuweisung an Position
length(x) + 1hängt ein unbenanntes Element an. - Die Zuweisung von
NULLentfernt das Element vollständig - die Liste wird kürzer. (Das ist die eine Stelle, an derNULLals Löschbefehl wirkt; musst du wirklich "nichts" in einem Fach speichern, nutzex["k"] <- list(NULL).)
Um zwei Listen aneinanderzukleben, funktioniert c() bei Listen genauso wie bei Vektoren: c(list_a, list_b) gibt eine längere Liste zurück.
Verschachtelte Listen
Weil ein Listenelement eine weitere Liste sein kann, verschachteln sich Listen beliebig tief - was sie zu R's natürlicher Form für strukturierte Daten wie geparstes JSON oder gruppierte Ergebnisse macht:
Das Eintauchen ist bloß eine Verkettung von Zugriffen - jedes $ oder [[ geht eine Ebene tiefer. Wenn eine verschachtelte Struktur verwirrend wird, zeigt str(company) den ganzen Baum auf einmal, und str(company, max.level = 1) nur die oberste Schicht.
Flach machen mit unlist()
unlist() klappt eine Liste - egal wie tief verschachtelt - in einen einzigen Vektor zusammen:
Zwei Dinge fallen auf. Erstens baut unlist() Namen für dich (math1, math2, art), sodass du noch erkennen kannst, woher jeder Wert stammt. Zweitens - und das ist die Falle - hält ein Vektor nur einen Typ, deshalb konvertiert das Unlisten einer gemischten Liste alles auf den flexibelsten vorhandenen Typ. Die Zahl 1 kam als Zeichenkette "1" zurück. Wenn du unlistest und deine Zahlen zu Text werden, war die Liste nicht so einheitlich, wie du dachtest.
Warum Listen wichtig sind
Listen können sich wie ein Anfängerthema anfühlen, das man hinter sich lässt. Es ist umgekehrt - sie sind tragend in der ganzen Sprache:
- Funktionen, die mehrere Dinge zurückgeben, geben eine Liste zurück. R-Funktionen geben ein Objekt zurück; eine Liste lässt dieses eine Objekt hier einen angepassten Wert und dort eine Koeffiziententabelle tragen. Führst du eine Regression aus, ist das zurückgegebene Modellobjekt eine (große, klassifizierte) Liste -
str()darauf beweist es. - Ein Data Frame ist eine Liste von Spalten - gleich lange Vektoren mit etwas Zusatzverhalten obendrauf. Alles, was du gerade gelernt hast (
$,[[, Zuweisung vonNULLzum Entfernen), gilt wortwörtlich für Data-Frame-Spalten. - Die apply-Familie -
lapply()und Co. - nimmt eine Liste, wendet eine Funktion auf jedes Element an und gibt eine Liste zurück. Listen rein, Listen raus ist die Standardform wiederholter Berechnung in R.
Was du mitnimmst
- Listen halten alles: gemischte Typen, ungleiche Längen, andere Listen, ganze Data Frames.
[gibt eine kleinere Liste zurück;[[gibt das Element selbst zurück;$ist[[mit wörtlichem Namen. Du willst rechnen? Dann brauchst du[[oder$.- Hinzufügen durch Zuweisung an einen neuen Namen, Entfernen durch Zuweisung von
NULL, Kombinieren mitc(). unlist()macht flach zu einem Vektor und konvertiert dabei gemischte Typen - prüfe die Klasse des Ergebnisses.- Data Frames sind Listen von Spalten, dieses Wissen überträgt sich also direkt.
Als Nächstes: Matrizen - das Ein-Typ-Gegenstück der Liste mit Zeilen und Spalten.
Häufig gestellte Fragen
Was ist der Unterschied zwischen [ und [[ in R?
Einfache Klammern [ geben immer eine Liste mit den ausgewählten Elementen zurück - einen kleineren Container derselben Art. Doppelte Klammern [[ greifen hinein und geben das Element selbst zurück. Enthält x$scores einen numerischen Vektor, dann ist x["scores"] eine Liste der Länge 1 und x[["scores"]] der numerische Vektor. Nutze [[ (oder $), wenn du tatsächlich mit dem Wert arbeiten willst.
Wie fügt man in R ein Element zu einer Liste hinzu?
Weise einem noch nicht existierenden Namen zu: x$email <- "rosa@example.com" oder x[["email"]] <- .... Die Liste wächst automatisch. Um ohne Namen anzuhängen, weise der nächsten Position zu: x[[length(x) + 1]] <- value. Um ein Element zu entfernen, weise ihm NULL zu: x$email <- NULL.
Wie wandelt man in R eine Liste in einen Vektor um?
unlist(x) macht eine Liste (auch verschachtelte) zu einem einzigen Vektor flach. Da ein Vektor nur einen Typ enthält, wird alles auf den flexibelsten vorhandenen Typ konvertiert - eine Liste aus Zahlen und Zeichenketten wird zu einem reinen Zeichenvektor. Prüfe nach dem Unlisten die class() des Ergebnisses.