A list in R is an ordered collection of items, differing from vectors in a few ways:
numeric with character).Analogies to other languages are imprecise.
An R list is somewhat similar to a Python dictionary, but the list is ordered and can be accessed by numerical index.
It is somewhat similar to a C struct, except that the list can easily be extended at runtime.
Giving names (often called "tags") to the elements is more common with lists than with vectors:
list(x = 5.3, y = 4.2, color = "blue")
#> $x
#> [1] 5.3
#> $y
#> [1] 4.2
#> $color
#> [1] "blue"
However, tags are optional and R will then just use index numbers:
list(5.3, 4.2, "blue")
#> [[1]]
#> [1] 5.3
#> [[2]]
#> [1] 4.2
#> [[3]]
#> [1] "blue"
There are three ways to do this, each useful in different contexts.
$tag notationVery common if the tag names are known in advance.
point <- list(x = 5.3, y = 4.2, color = "blue")
#> point$x
#> [1] 5.3
#> point$color
#> [1] "blue"
[[tag]] notationThis has the advantage that the tag name can be chosen at runtime. Note the double brackets.
want <- "y"
point[[want]] # same as point$y
#> [1] 4.2
This works whether or not the list has tags. Again, brackets are doubled.
point[[3]] # same as point$color
#> [1] "blue"
Simple: assigning to an element will modify if it exists or insert if it is new.
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
To delete, assign NULL to the unwanted element.
point$trust <- NULL
str(point)
#> List of 3
#> $ x : num 5.3
#> $ y : num 4.2
#> $ color: chr "red"
The vector class is technically known as atomic vector, because it can only hold atomic values: numeric, character, boolean, etc.
Because a list can contain other lists, it is also known as a recursive vector.
As well as being a technical point of nomenclature, this is a reminder that lists can have arbitrarily complex structure. It is the programmer's responsibility to understand what will be provided when accessing a list element.
Some examples above used double brackets [[ ]] to access list emements.
This will try to flatten the element to its underlying type, which is useful if you just want a number or a string.
Using single brackets [ ] will not do this flattening, and the returned value will be a sublist.
point[["color"]]
#> [1] "red" # flattened
point["color"]
#> $color
#> [1] "red" # sublist
Even if the sublist is not what a novice R programmer is likely to want, please be aware of it.
For maximum flexibility, many standard R functions return a list, even when it contains a single atomic value as here.
To convert to a vector there are two possibilities.
[[1]]
unlist() function.pt <-point["color"]
pt[[1]]
#> [1] "red" # simple 1-element vector
unlist(pt)
#> color
#> "red" # 1-element vector with name
Be careful with unlist().
Flattening the structure is useful in this simple case, but can cause surprises with more complicated list elements.
A list, like an atomic vector, is stored contiguously. The difference is that numeric and boolean vectors store values, but the list stores references to objects located elsewhere in memory.
Knowing this is rarely important for an R user, but in a polyglot community like Exercism it may be helpful to programmers familiar with other languages.