9  Lists in R

Learning Objectives: After this chapter you will be able to:

  • Create a list that holds elements of different types.
  • Name list elements with names().
  • Access elements with [[, [, and $.
  • Explain why [[ returns the element while [ returns a list.
  • Convert a vector or matrix into a list with as.list().
  • Convert a list back into a vector with unlist().

9.1 Introduction

Lists are very useful as they are heterogeneous i.e. they can contain different data types. If you remember, vectors and matrices are homogeneous i.e. they can contain only one type of data. If you include different data types, they will all be coerced to the same type. With lists, it is different. In this chapter, we will delve deeper into lists.

9.2 Creating Lists

To create a list, we use the list() function. Let us create a simple list to demonstrate how they can contain different data types.

# numeric vector
vect1 <- 1:10

# character vector 
vect2 <- c('Jack', 'John', 'Jill')

# logical vector
vect3 <- c(TRUE, FALSE)

# matrix
mat <- matrix(data = 1:9, nrow = 3)

# list
l <- list(vect1, vect2, vect3, mat)
l
[[1]]
 [1]  1  2  3  4  5  6  7  8  9 10

[[2]]
[1] "Jack" "John" "Jill"

[[3]]
[1]  TRUE FALSE

[[4]]
     [,1] [,2] [,3]
[1,]    1    4    7
[2,]    2    5    8
[3,]    3    6    9

If you observe the output, all the elements of the list retain their data types. Now let us learn how to access the elements of the list.

9.3 Access List Elements

You can access the elements of a list using the following operators:

  • [[
  • [
  • $

Let us try them one by one.

# using [[
l[[1]]
 [1]  1  2  3  4  5  6  7  8  9 10
# using [
l[1]
[[1]]
 [1]  1  2  3  4  5  6  7  8  9 10

[[ extracts the element itself (which may be a vector, matrix, data frame, or nested list), while [ returns a new list containing the selected element(s). The $ operator can be used only when we have named elements in the list. Let us add names to the elements. Use the names() function to add names to the list.

# named elements
names(l) <- c('vect1', 'vect2', 'vect3', 'mat')
l
$vect1
 [1]  1  2  3  4  5  6  7  8  9 10

$vect2
[1] "Jack" "John" "Jill"

$vect3
[1]  TRUE FALSE

$mat
     [,1] [,2] [,3]
[1,]    1    4    7
[2,]    2    5    8
[3,]    3    6    9
# use $
l$vect1
 [1]  1  2  3  4  5  6  7  8  9 10
# use [[
l[['vect1']]
 [1]  1  2  3  4  5  6  7  8  9 10
# use [
l['vect1']
$vect1
 [1]  1  2  3  4  5  6  7  8  9 10

9.4 Coerce other objects

You can coerce other objects to list using as.list().

# vector
vect1 <- 1:10
as.list(vect1)
[[1]]
[1] 1

[[2]]
[1] 2

[[3]]
[1] 3

[[4]]
[1] 4

[[5]]
[1] 5

[[6]]
[1] 6

[[7]]
[1] 7

[[8]]
[1] 8

[[9]]
[1] 9

[[10]]
[1] 10
# matrix
mat <- matrix(data = 1:9, nrow = 3)
as.list(mat)
[[1]]
[1] 1

[[2]]
[1] 2

[[3]]
[1] 3

[[4]]
[1] 4

[[5]]
[1] 5

[[6]]
[1] 6

[[7]]
[1] 7

[[8]]
[1] 8

[[9]]
[1] 9

9.5 Coerce list to other objects

Use unlist() to coerce a list to a vector.

# unlist
unlist(l)
 vect11  vect12  vect13  vect14  vect15  vect16  vect17  vect18  vect19 vect110 
    "1"     "2"     "3"     "4"     "5"     "6"     "7"     "8"     "9"    "10" 
 vect21  vect22  vect23  vect31  vect32    mat1    mat2    mat3    mat4    mat5 
 "Jack"  "John"  "Jill"  "TRUE" "FALSE"     "1"     "2"     "3"     "4"     "5" 
   mat6    mat7    mat8    mat9 
    "6"     "7"     "8"     "9" 
# remove names
unlist(l, use.names = FALSE)
 [1] "1"     "2"     "3"     "4"     "5"     "6"     "7"     "8"     "9"    
[10] "10"    "Jack"  "John"  "Jill"  "TRUE"  "FALSE" "1"     "2"     "3"    
[19] "4"     "5"     "6"     "7"     "8"     "9"    

9.6 Practice Check

Knowledge Check: Why use a list at all? vect1 <- 1:10, vect2 <- c('Jack', 'John', 'Jill'), and vect3 <- c(TRUE, FALSE). Why not just c(vect1, vect2, vect3)?

Click to reveal answer

Answer: That would coerce everything to character, because character is the most flexible type. A list keeps each element’s own type.

Explanation: c(vect1, vect2, vect3) gives you c("1", "2", ..., "10", "Jack", ...). Vectors and matrices are homogeneous, so mixing types destroys information. list(vect1, vect2, vect3) stores the three vectors side by side with their types intact.

Knowledge Check: [[ versus [ Given l <- list(1:10, c('Jack', 'John')), what is the difference between l[[1]] and l[1]?

Click to reveal answer

Answer: l[[1]] is the vector 1:10 itself. l[1] is a list containing one element, which is that same vector.

Explanation: [[ extracts the element, so you get the object and can operate on it directly. [ builds a new list holding the selection, which is what you want when you want to delete or keep several elements. Square brackets are for selecting; double square brackets are for extracting.

Knowledge Check: $ needs names Why does l$vect1 fail before you run names(l) <- c('vect1', 'vect2', 'vect3', 'mat')?

Click to reveal answer

Answer: The elements have no names, so there is nothing for $ to match.

Explanation: $ looks up elements by name, not by position. Until the list has names, use l[[1]] or l[1]. Once named, l$vect1 and l[['vect1']] both return the vector.

Knowledge Check: Coercing to a list How do you turn the vector vect1 <- 1:10 into a list, one element per value?

Click to reveal answer

Answer: as.list(vect1), which gives a list of ten single numbers.

Explanation: as.list() splits the vector into its individual elements. The same call works on a matrix, in which case it splits the matrix into columns. The reverse direction is unlist().

Knowledge Check: Flattening a list What does unlist(l, use.names = FALSE) do differently from unlist(l)?

Click to reveal answer

Answer: It returns the same values but without the names.

Explanation: unlist() concatenates every element into one vector and keeps the names it finds, so you get a named vector. Setting use.names = FALSE drops the names, which is usually what you want for further calculation.