l1 <- list(
name = "bob",
alive = TRUE,
age = 33,
relationshipStatus = 42 + 3i
)
l1$name[1] "bob"
class(l1$name)[1] "character"
Like vectors and matrices, we can access and modify the slots of a list. Unlike those simpler data objects, however, we have several different ways to select list elements (not just the [] operator).
R provides several mechanisms for accessing the contents of a list, each serving a distinct purpose. The three main operators used for this task are the dollar sign ($), single brackets ([]), and double brackets ([[]]).
The $ operator accesses a single list slot by name and returns the contents of that list slot.
[1] "bob"
[1] "character"
The [[]] operator works like the $ operator but also accepts numeric indices.
The [] operator is notably different: it extracts any number of list slots and returns the result as a list. Even if we only select one element, the [] operator still returns a list. This behavior is useful when we want to retain the list structure for further processing.
$name
[1] "bob"
$alive
[1] TRUE
[1] "list"
$name
[1] "bob"
$alive
[1] TRUE
$name
[1] "bob"
$alive
[1] TRUE
[1] "list"
If we want to select multiple list elements, the [] operator is our only option. You cannot use the $ or [[]] operators to select multiple list slots.
Error in `l1[[1:2]]`:
! subscript out of bounds
Error:
! attempt to apply non-function
$, [[]], and []
To gain some intuition for the different flavors of list subsetting, you can think of a list as a stack of moving boxes.
Let’s consider a three-slot list as our example. We’ll conceptualize this list as a stack of three boxes (box = list slot). Let’s say the first box contains clothes (pile of clothes = some kind of vector), the second box contains books (stack of books = different kind of vector), and the third box contains four smaller boxes (set of smaller boxes = nested list) that hold various types of kitchen supplies.
The $ and [[]] operators work like reaching inside a single box and retrieving its contents.
In our analogy, these two operators unpack a single box. For example, we might remove the books from the second box and place them on a bookshelf. We’re not interested in the box; we’re directly interacting with the books.
The [] operator works like choosing one or more unopened boxes from our stack and doing something with those boxes.
In our analogy, this operator picks up some boxes but doesn’t open them. For example, we might pick up the first two boxes and move them to our bedroom. This time, we’re only interacting with the boxes; we’re not concerned with anything inside the boxes.
If you’re ever surprised that a selection “is still a list” when you expected the raw value from the list slot, check whether you used [] (which always keeps the list wrapper) instead of $ or [[]] (which unwrap the selected value).
Predict: What type of object will the following code print?
The command someList$c returns a list because the c slot in someList holds another list. Nothing special happens here: using the single element extraction procedure returns the contents of the c slot, as it always does. In this case, those contents just happen to be another list. In terms of our “Moving Day” analogy, running someList$c is like unpacking the third box. After unpacking, we’re left with more boxes, since the third box only contained a set of smaller boxes.
This example is meant as a warning against overgeneralizing simple rules. Don’t fall into the trap of thinking that $ and [[]] never return a list. Both of these operators will return a list, when the selected slot holds a list.
As with vectors and matrices, you shouldn’t think about the list selection operators ($, [], [[]]) as “subsetting operators”. It’s better to think about the selection operators as designating some part of a list for further processing. In the above examples, the further processing was simply printing the selected elements to the R console, but we can also use the selection operators to modify the designated list elements.
$name
[1] "bob"
$alive
[1] TRUE
$age
[1] 33
$relationshipStatus
[1] 42+3i
# Modify some list elements
l1$age <- 57
l1[[1]] <- "suzy"
l1[c(2, 4)] <- c("foo", "bar")
# View the modified list
l1$name
[1] "suzy"
$alive
[1] "foo"
$age
[1] 57
$relationshipStatus
[1] "bar"
Lists in R do not require a fixed length or predefined structure. New elements can be added at any point, either by position or by name. This flexibility makes lists well suited for incremental construction.
list()
$grass
[1] "green"
$logical
[1] FALSE
[[3]]
[1] 1 2 3 4
Use the list that you created in the last practice problem for this exercise.
Replace the character vector that you assigned to the hair slot with a two-slot list comprising two length-one character vectors.
hair slot.Recall my solution for the last practice problem.
I would modify my list as follows.
Importantly, the types of the objects you store in a list are maintained.
[1] "integer"
[1] "integer"
[1] "list"
[1] "list"
[1] "character"
[1] "character"
Consequently, objects stored in a list behave just as they would outside of the list. For example, if we store a function as an element of a list, we can call that function directly from within the list.
# Store the Base R 'mean' function in the 'l3' list
l3$myMean <- mean
# Call the normal 'mean' function
mean(1:5)[1] 3
[1] 3
Use the list that you created in the last practice problem for this exercise.
Using a single command, test if your eye color OR your hair color is also your favorite color.
Recall the basic logical operators:
==, !=: Equal, Not Equal>, <, >=, <=: Greater Than, Less Than&, |: Logical AND, Logical OR (not exclusive)l$x returns an error but l[["x"]] works, what does that tell you about l?name slot in the list l does not hold another list, why would l["name"] return a list, while l[["name"]] returns some other type of object?You’re ready to move on to Data Frames if you can:
$, [], and [[]], and choose the right one for a given task.If any of these still feel shaky, revisit the relevant page above, or try the Knowledge Quiz to pinpoint exactly where to focus.