Eine list in R ist eine geordnete Sammlung von Elementen, die sich in einigen Punkten von vectors unterscheidet:
numeric mit character gemischt).Vergleiche mit anderen Sprachen sind ungenau.
Eine R-list ähnelt ein wenig einem Python-Dictionary, aber die list ist geordnet und lässt sich über einen numerischen Index ansprechen.
Sie ähnelt auch ein wenig einem C-struct, nur dass sich die list zur Laufzeit leicht erweitern lässt.
Elementen Namen (oft „Tags“ genannt) zu geben, ist bei Listen üblicher als bei Vektoren:
list(x = 5.3, y = 4.2, color = "blue")
#> $x
#> [1] 5.3
#> $y
#> [1] 4.2
#> $color
#> [1] "blue"
Tags sind aber optional, und R verwendet dann einfach Indexnummern:
list(5.3, 4.2, "blue")
#> [[1]]
#> [1] 5.3
#> [[2]]
#> [1] 4.2
#> [[3]]
#> [1] "blue"
Dafür gibt es drei Möglichkeiten, die jeweils in unterschiedlichen Situationen nützlich sind.
$tag-NotationSehr verbreitet, wenn die Tag-Namen im Voraus bekannt sind.
point <- list(x = 5.3, y = 4.2, color = "blue")
#> point$x
#> [1] 5.3
#> point$color
#> [1] "blue"
[[tag]]-NotationDas hat den Vorteil, dass der Tag-Name zur Laufzeit gewählt werden kann. Beachte die doppelten Klammern.
want <- "y"
point[[want]] # same as point$y
#> [1] 4.2
Das funktioniert unabhängig davon, ob die Liste Tags hat. Auch hier werden die Klammern verdoppelt.
point[[3]] # same as point$color
#> [1] "blue"
Ganz einfach: Eine Zuweisung an ein Element ändert es, wenn es existiert, und fügt es ein, wenn es neu ist.
point$color <- "red"
point$trust <- TRUE
# str() gives more compact output than the default display
str(point)
#> List of 4
#> $ x : num 5.3
#> $ y : num 4.2
#> $ color: chr "red"
#> $ trust: logi TRUE
Zum Löschen weist du dem unerwünschten Element NULL zu.
point$trust <- NULL
str(point)
#> List of 3
#> $ x : num 5.3
#> $ y : num 4.2
#> $ color: chr "red"
Die Klasse vector heißt technisch atomic vector, weil sie nur atomare Werte aufnehmen kann: numeric, character, boolean usw.
Weil eine list andere Listen enthalten kann, wird sie auch als recursive vector bezeichnet.
Das ist nicht nur ein Punkt der Namensgebung, sondern auch eine Erinnerung daran, dass Listen beliebig komplexe Strukturen haben können. Es liegt in deiner Verantwortung als Programmierer, zu verstehen, was beim Zugriff auf ein Listenelement geliefert wird.
Einige Beispiele oben haben doppelte Klammern [[ ]] verwendet, um auf Listenelemente zuzugreifen.
Dabei wird versucht, das Element auf seinen zugrunde liegenden Typ zu reduzieren, was nützlich ist, wenn du nur eine Zahl oder einen String möchtest.
Einfache Klammern [ ] machen diese Reduktion nicht, und der zurückgegebene Wert ist eine Teilliste.
point[["color"]]
#> [1] "red" # flattened
point["color"]
#> $color
#> [1] "red" # sublist
Auch wenn die Teilliste nicht das ist, was eine unerfahrene R-Programmiererin oder ein unerfahrener R-Programmierer vermutlich möchte, solltest du dir dessen bewusst sein.
Aus Gründen der Flexibilität geben viele Standardfunktionen von R eine list zurück, selbst wenn sie wie hier nur einen einzigen atomaren Wert enthält.
Um in einen Vektor umzuwandeln, gibt es zwei Möglichkeiten.
[[1]]
unlist().pt <-point["color"]
pt[[1]]
#> [1] "red" # simple 1-element vector
unlist(pt)
#> color
#> "red" # 1-element vector with name
Sei vorsichtig mit unlist().
In diesem einfachen Fall ist es nützlich, die Struktur zu reduzieren, bei komplizierteren Listenelementen kann es aber Überraschungen geben.
Eine list wird, wie ein atomarer vector, zusammenhängend gespeichert. Der Unterschied ist, dass numerische und boolesche Vektoren Werte speichern, die Liste aber Referenzen auf Objekte, die an anderer Stelle im Speicher liegen.
Das zu wissen ist für R-Nutzende selten wichtig, aber in einer mehrsprachigen Community wie Exercism kann es für Programmierer hilfreich sein, die mit anderen Sprachen vertraut sind.