17 Lists

In this chapter, you will learn about R lists, the most generic type of data container in R.

  • Lists are the most general class of data container
  • Like vectors, lists group data into a one-dimensional set
  • Unlike vectors, lists can store all kinds of objects
  • Lists can be of any length
  • Elements of a list can be named, or not

17.1 Creating Lists

The typical way to create a list is with the function list(). This function creates a list the same way c() creates a vector. Let’s start with a simple example creating three numeric vectors of same length, that we then use to store them in a list:

vec1 <- 1:3
vec2 <- 4:6
vec3 <- 7:9

# list with unnamed elements
lis <- list(vec1, vec2, vec3)
lis
#> [[1]]
#> [1] 1 2 3
#> 
#> [[2]]
#> [1] 4 5 6
#> 
#> [[3]]
#> [1] 7 8 9

Note how the contents of a list with unnamed elements are displayed: there is a set of double brackets with an index indicating the position of each element, and below each double bracket the corresponding vector is printed.

For illustration purposes, we could visualize the three input vectors and the list with the following conceptual diagram.

A list containing three unnamed elements (numeric vectors of length 3)

Figure 17.1: A list containing three unnamed elements (numeric vectors of length 3)

Our intention with the depicted list as a set of discontinuous cells is to convey the idea that a list is also a one-dimensional vector, albeit a very special type of vector: a non-atomic vector. This means that each element of a list can be any kind of object.

In the same way you can give names to elements of a vector, you can also give names to elements of a list:

# list with named elements
lis <- list("vec1" = vec1, "vec2" = vec2, "vec3" = vec3)
lis
#> $vec1
#> [1] 1 2 3
#> 
#> $vec2
#> [1] 4 5 6
#> 
#> $vec3
#> [1] 7 8 9

When you create a list in this form, you can actually omit the quotes of the given names. While this option of naming elements may create a bit of confusion for beginners and inexperienced users in R, we believe it’s not a big deal (based on our experience):

# another option for giving names to elements in a list
lis <- list(vec1 = vec1, vec2 = vec2, vec3 = vec3)
lis
#> $vec1
#> [1] 1 2 3
#> 
#> $vec2
#> [1] 4 5 6
#> 
#> $vec3
#> [1] 7 8 9

Observe how the contents of a list with named elements are displayed: now, instead of the set of double brackets, there is a dollar sign followed by the name of the element, e.g. $vec1. Below each name, the corresponding vector is printed.

The conceptual diagram in this case could look like this:

A list with named elements (numeric vectors of length 3)

Figure 17.2: A list with named elements (numeric vectors of length 3)

As we just said, the elements of a list can be any kind of R object. For example, here’s a list called lst that contains a character vector, a numeric matrix, a factor, and another list:

lst <- list(
  c("Harry", "Ron", "Hermione"),
  matrix(1:6, nrow = 2, ncol = 3),
  factor(c("yes", "no", "no", "no", "yes")),
  list("Harry", "Ron", "Hermione")
)

lst
#> [[1]]
#> [1] "Harry"    "Ron"      "Hermione"
#> 
#> [[2]]
#>      [,1] [,2] [,3]
#> [1,]    1    3    5
#> [2,]    2    4    6
#> 
#> [[3]]
#> [1] yes no  no  no  yes
#> Levels: no yes
#> 
#> [[4]]
#> [[4]][[1]]
#> [1] "Harry"
#> 
#> [[4]][[2]]
#> [1] "Ron"
#> 
#> [[4]][[3]]
#> [1] "Hermione"

Whenever possible, we strongly recommend giving names to the elements of a list. Not only this makes it easy to identify one element from the others, but it also gives you more flexibility to rearrange the contents of the list without having to worry about the exact order or position they occupy.

# whenever possible, give names to elements in a list
lst <- list(
  first = c("Harry", "Ron", "Hermione"),
  second = matrix(1:6, nrow = 2, ncol = 3),
  third = factor(c("yes", "no", "no", "no", "yes")),
  fourth = list("Harry", "Ron", "Hermione")
)

17.2 Manipulating Lists

To manipulate the elements of a list you can use bracket notation. Because a list is a vector, you can use single brackets (e.g. lis[1]) as well as double brackets (e.g. lis[[1]]).

Bracket notation with lists

Figure 17.3: Bracket notation with lists

17.2.1 Single brackets

Just like any other vector, and any other data object in R, you can use single brackets on a list. For example, consider the unnamed version of a list, and the use of single brackets with index 1 inside them:

# list with unnamed elements
lis <- list(vec1, vec2, vec3)

lis[1]
#> [[1]]
#> [1] 1 2 3

What a single bracket does, is give you access to the “container” of the specified element but without “unboxing” its contents. This is reflected by the way in which the output is displayed: note the double bracket [[1]] in the first line, and then [1] 1 2 3 in the second line.

In other words, lis[1] gives you the first element of the list, which contains a vector, but it does not give you direct access to the vector itself. Put another way, lis[1] lets you see that the first element of the list is a vector, but this vector is still inside its “box”.

Use single brackets to select an element

Figure 17.4: Use single brackets to select an element

17.2.2 Double Brackets

In addition to single brackets, lists also accept double brackets: e.g.  lis[[1]]

lis[[1]]
#> [1] 1 2 3

Double brackets are used when you want to get access to the content of the list’s elements. Notice the output of the previous command: now there are no double brackets, just the output of the vector in the first position. Think of this command as “unboxing” the object of the first element in lis.

What if you want to manipulate the elements of vector vec1 or vec2? Use double brackets followed by single brackets

# second index of first list's element
lis[[1]][2]
#> [1] 2

# first index of second list's element
lis[[2]][1]
#> [1] 4
Use double brackets to extract an element

Figure 17.5: Use double brackets to extract an element

17.2.3 Dollar signs

R lists—and data frames—follow an optional second system of notation for extracting named elements using the dollar sign $

Dollar notation with lists

Figure 17.6: Dollar notation with lists

Let’s use the named version of lis:

# list with named elements
lis <- list("vec1" = vec1, "vec2" = vec2, "vec3" = vec3)

lis$vec1
#> [1] 1 2 3

The dollar sign $ notation works for selecting named elements in a list. Notice the output of the above command: lis$vec1 gives you vector 1 2 3. In other words, dollar notation “unboxes” the object that is associated to the specified name.

17.2.4 Adding new elements

From time to time, you will want to add one or more elements to an existing list. For instance, consider a list lst with two elements:

lst <- list(1:3, c('A', 'B', 'C'))

lst
#> [[1]]
#> [1] 1 2 3
#> 
#> [[2]]
#> [1] "A" "B" "C"

Say you want to add a logical vector as a third element to lst. One option to do this is with double brackets, specifying a new index position to which you assign the new element:

lst[[3]] <- c(TRUE, FALSE, TRUE, FALSE)

lst
#> [[1]]
#> [1] 1 2 3
#> 
#> [[2]]
#> [1] "A" "B" "C"
#> 
#> [[3]]
#> [1]  TRUE FALSE  TRUE FALSE

Another option is to use the dollar operator by giving a new name to which you assign the new element. Even though the previous elements in lstare unnamed, the new added element will have an associated label:

lst$new_elem <- 'nuevo'

lst
#> [[1]]
#> [1] 1 2 3
#> 
#> [[2]]
#> [1] "A" "B" "C"
#> 
#> [[3]]
#> [1]  TRUE FALSE  TRUE FALSE
#> 
#> $new_elem
#> [1] "nuevo"

17.2.5 Removing elements

Just like you will want to add new elements in a list, you will also find occasions in which you need to remove one or more elements. Take the previous list lst with four elements, and say you want to remove the third element (containing the logical vector)

lst
#> [[1]]
#> [1] 1 2 3
#> 
#> [[2]]
#> [1] "A" "B" "C"
#> 
#> [[3]]
#> [1]  TRUE FALSE  TRUE FALSE
#> 
#> $new_elem
#> [1] "nuevo"

To remove the third element, which is unnamed, you use double brackets and assign a value NULL to that position:

lst[[3]] <- NULL
lst
#> [[1]]
#> [1] 1 2 3
#> 
#> [[2]]
#> [1] "A" "B" "C"
#> 
#> $new_elem
#> [1] "nuevo"

As for those named elements, such as lst$new_elem, you do the same and assign a NULL value, but this time using dollar notation:

lst$new_elem <- NULL
lst
#> [[1]]
#> [1] 1 2 3
#> 
#> [[2]]
#> [1] "A" "B" "C"

17.2.6 Slides

17.3 Exercises

1) How would you create a list with your first name, middle name, and last name? For example, something like:

$first
[1] "Gaston"

$middle
NULL

$last
[1] "Sanchez"

2) Consider an R list student containing the following elements:

$name
[1] "Luke Skywalker"

$major_minor
              major               minor 
     "jedi studies" "imperial policies" 

$gpa
[1] 4

$grades
           course score
1       force-101   9.3
2    light-sabers  10.0
3 jedi-literature   8.5

What is the output of the following commands? Try to guess the answer without running the code.

  1. student$grades$semester <- 4

  2. sum(student[[2]] == "sith philosophy")

  3. student["sid"] <- as.integer("123456")

  4. mean(student[[4]][1:3,2], na.rm = TRUE)

  5. student[[4]] <- student$grades[c(FALSE, TRUE, TRUE), ]