Lists
Learning objectives
In this section you will learn about lists,
- What is a list
- How to create a list?
- How to access the elements of a list?
- How to manipulate the elements of a list?
- How to merge lists?
What is a R List?
Lists are R objects that contain elements of different types like numbers, strings, vectors or even another list inside it. A list can also contain a matrix or a function as its elements.
How to create a list?
To create a list you can use the list()
function and declare the elements
ans <- list("Red", "Green", c(21,32,11), TRUE, 51.23, 119.1)
ans
## [[1]]
## [1] "Red"
##
## [[2]]
## [1] "Green"
##
## [[3]]
## [1] 21 32 11
##
## [[4]]
## [1] TRUE
##
## [[5]]
## [1] 51.23
##
## [[6]]
## [1] 119.1
class(ans)
## [1] "list"
You just created a list with 6 elements, the first two elements being characters, the third element being a numeric vector, etc.
The list elements can be given names and they can be accessed using these names.
ans <- list(c("Jan","Feb","Mar"), c(3,9,5,1,-2,8),list("green",12.3))
names(ans) <- c("First Quarter", "A_Vector", "A Inner list")
ans
## $`First Quarter`
## [1] "Jan" "Feb" "Mar"
##
## $A_Vector
## [1] 3 9 5 1 -2 8
##
## $`A Inner list`
## $`A Inner list`[[1]]
## [1] "green"
##
## $`A Inner list`[[2]]
## [1] 12.3
Alternatively, you can define the names directly while creating the list:
ans <- list(firstQarter = c("Jan","Feb","Mar"), aVector = c(3,9,5,1,-2,8), anInnerList = list("green",12.3))
ans
## $firstQarter
## [1] "Jan" "Feb" "Mar"
##
## $aVector
## [1] 3 9 5 1 -2 8
##
## $anInnerList
## $anInnerList[[1]]
## [1] "green"
##
## $anInnerList[[2]]
## [1] 12.3
You can also create an empty list, for information to be added later on
If you do not know the structure of the list in advance, you can simply use the function list()
without arguments.
ans <- list( )
ans
## list()
If you know exactly how many elements you want to create, you can use the following syntax:
ans <- vector("list", 3)
ans
## [[1]]
## NULL
##
## [[2]]
## NULL
##
## [[3]]
## NULL
How to analyse the structure of a list
In many cases, you will not create a list yourself. Instead, many package functions create complex outputs in the form of lists. The packages usually provide summary functions to display these results. However, sometimes, you will need to access specific part of the output for further analyses.
We will take the example of linear regression.
Do not worry for the moment on how it works, just the following commands.
# install.packages("wooldridge") # if not installed on your machine only
library(wooldridge)
## Warning: package 'wooldridge' was built under R version 4.0.5
data(wage2) # load the data set
lr <- lm(wage ~ IQ + age, data=wage2) # run a linear regression & save the results in lr
When you display the object lr, it is in fact giving you only a tiny portion of all the information contained in the object.
lr
##
## Call:
## lm(formula = wage ~ IQ + age, data = wage2)
##
## Coefficients:
## (Intercept) IQ age
## -637.363 8.503 22.190
In fact, the output of a linear regression is a list with 12 elements. In order to see the complete structure of the list, you can use the function str()
:
str(lr)
## List of 12
## $ coefficients : Named num [1:3] -637.4 8.5 22.2
## ..- attr(*, "names")= chr [1:3] "(Intercept)" "IQ" "age"
## $ residuals : Named num [1:935] -72.4 -387.6 -188.3 -239.1 -184.4 ...
## ..- attr(*, "names")= chr [1:935] "1" "2" "3" "4" ...
## $ effects : Named num [1:935] -29292 -3820 2106 -239 -206 ...
## ..- attr(*, "names")= chr [1:935] "(Intercept)" "IQ" "age" "" ...
## $ rank : int 3
## $ fitted.values: Named num [1:935] 841 1196 1013 889 746 ...
## ..- attr(*, "names")= chr [1:935] "1" "2" "3" "4" ...
## $ assign : int [1:3] 0 1 2
## $ qr :List of 5
## ..$ qr : num [1:935, 1:3] -30.5778 0.0327 0.0327 0.0327 0.0327 ...
## .. ..- attr(*, "dimnames")=List of 2
## .. .. ..$ : chr [1:935] "1" "2" "3" "4" ...
## .. .. ..$ : chr [1:3] "(Intercept)" "IQ" "age"
## .. ..- attr(*, "assign")= int [1:3] 0 1 2
## ..$ qraux: num [1:3] 1.03 1.04 1
## ..$ pivot: int [1:3] 1 2 3
## ..$ tol : num 1e-07
## ..$ rank : int 3
## ..- attr(*, "class")= chr "qr"
## $ df.residual : int 932
## $ xlevels : Named list()
## $ call : language lm(formula = wage ~ IQ + age, data = wage2)
## $ terms :Classes 'terms', 'formula' language wage ~ IQ + age
## .. ..- attr(*, "variables")= language list(wage, IQ, age)
## .. ..- attr(*, "factors")= int [1:3, 1:2] 0 1 0 0 0 1
## .. .. ..- attr(*, "dimnames")=List of 2
## .. .. .. ..$ : chr [1:3] "wage" "IQ" "age"
## .. .. .. ..$ : chr [1:2] "IQ" "age"
## .. ..- attr(*, "term.labels")= chr [1:2] "IQ" "age"
## .. ..- attr(*, "order")= int [1:2] 1 1
## .. ..- attr(*, "intercept")= int 1
## .. ..- attr(*, "response")= int 1
## .. ..- attr(*, ".Environment")=<environment: R_GlobalEnv>
## .. ..- attr(*, "predvars")= language list(wage, IQ, age)
## .. ..- attr(*, "dataClasses")= Named chr [1:3] "numeric" "numeric" "numeric"
## .. .. ..- attr(*, "names")= chr [1:3] "wage" "IQ" "age"
## $ model :'data.frame': 935 obs. of 3 variables:
## ..$ wage: int [1:935] 769 808 825 650 562 1400 600 1081 1154 1000 ...
## ..$ IQ : int [1:935] 93 119 108 96 74 116 91 114 111 95 ...
## ..$ age : int [1:935] 31 37 33 32 34 35 30 38 36 36 ...
## ..- attr(*, "terms")=Classes 'terms', 'formula' language wage ~ IQ + age
## .. .. ..- attr(*, "variables")= language list(wage, IQ, age)
## .. .. ..- attr(*, "factors")= int [1:3, 1:2] 0 1 0 0 0 1
## .. .. .. ..- attr(*, "dimnames")=List of 2
## .. .. .. .. ..$ : chr [1:3] "wage" "IQ" "age"
## .. .. .. .. ..$ : chr [1:2] "IQ" "age"
## .. .. ..- attr(*, "term.labels")= chr [1:2] "IQ" "age"
## .. .. ..- attr(*, "order")= int [1:2] 1 1
## .. .. ..- attr(*, "intercept")= int 1
## .. .. ..- attr(*, "response")= int 1
## .. .. ..- attr(*, ".Environment")=<environment: R_GlobalEnv>
## .. .. ..- attr(*, "predvars")= language list(wage, IQ, age)
## .. .. ..- attr(*, "dataClasses")= Named chr [1:3] "numeric" "numeric" "numeric"
## .. .. .. ..- attr(*, "names")= chr [1:3] "wage" "IQ" "age"
## - attr(*, "class")= chr "lm"
This is not the purpose of this class to comment these results. But you can see that although you will probably not create lists by yourself, you still need to understand how they function!
How to access the elements of a list
ans <- list(1:10, 11:20, list(letters[1:10], letters[11:20]))
ans
## [[1]]
## [1] 1 2 3 4 5 6 7 8 9 10
##
## [[2]]
## [1] 11 12 13 14 15 16 17 18 19 20
##
## [[3]]
## [[3]][[1]]
## [1] "a" "b" "c" "d" "e" "f" "g" "h" "i" "j"
##
## [[3]][[2]]
## [1] "k" "l" "m" "n" "o" "p" "q" "r" "s" "t"
To access the different elements of a list you can use the [ ]
or the [[ ]]
accessors. To understand the difference between the two approaches, you can compare the type of objects they output as in the following code:
ans <- list(1:10, 11:20, list(letters[1:10], letters[11:20]))
ans[2]
## [[1]]
## [1] 11 12 13 14 15 16 17 18 19 20
class(ans[2])
## [1] "list"
ans[[2]]
## [1] 11 12 13 14 15 16 17 18 19 20
class(ans[[2]])
## [1] "integer"
The [ ]
accessor will return a list (in this case a one element list). The [[ ]]
will return the actual content of the second element, in our case a numeric vector. So if you want to edit the vector, you need to use the [[ ]]
accessor.
In the case of a inner list, i.e., a list as an element of the list. The same rules apply:
ans <- list(1:10, 11:20, list(letters[1:10], letters[11:20]))
ans[3]
## [[1]]
## [[1]][[1]]
## [1] "a" "b" "c" "d" "e" "f" "g" "h" "i" "j"
##
## [[1]][[2]]
## [1] "k" "l" "m" "n" "o" "p" "q" "r" "s" "t"
ans[[3]][1]
## [[1]]
## [1] "a" "b" "c" "d" "e" "f" "g" "h" "i" "j"
ans[[3]][[1]]
## [1] "a" "b" "c" "d" "e" "f" "g" "h" "i" "j"
ans[[3]][[1]][2]
## [1] "b"
Finally, in the case of named list, you can access the different parts of the list via their names (or their corresponding numbers). Names ensure that you are accessing exactly the data you are looking for.
ans <- list(firstQuarter = c("Jan","Feb","Mar"),
aVector = c(3,9,5,1,-2,8),
anInnerList = list(color = "green", size =12.3))
ans["aVector"]
## $aVector
## [1] 3 9 5 1 -2 8
ans["anInnerList"]
## $anInnerList
## $anInnerList$color
## [1] "green"
##
## $anInnerList$size
## [1] 12.3
ans[["anInnerList"]][1]
## $color
## [1] "green"
ans[["anInnerList"]][[1]]
## [1] "green"
How to manipulate (add/edit/delete) the elements of a list
ans <- list()
# add new elements
ans[["first"]] <- 1:10
ans[["second"]] <- 11:25
ans[[3]] <- letters[1:10]
#edit existing elements
ans[["first"]] <- 1:10 / 10
#delete elements
ans[[2]] <- NULL
ans
## $first
## [1] 0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9 1.0
##
## [[2]]
## [1] "a" "b" "c" "d" "e" "f" "g" "h" "i" "j"
How to merge lists?
You can merge several lists into one list using the function c()
list1 <- list(1:5,2:3)
list2 <- list("Sun","Mon")
merged.list <- c(list1,list2)
merged.list
## [[1]]
## [1] 1 2 3 4 5
##
## [[2]]
## [1] 2 3
##
## [[3]]
## [1] "Sun"
##
## [[4]]
## [1] "Mon"
You can also merge a vector and a list with the c() function; however, each element of the vector becomes a new element of the list.
lis <- list(1:5,2:3)
vec <- c("Sun","Mon")
c(lis,vec)
## [[1]]
## [1] 1 2 3 4 5
##
## [[2]]
## [1] 2 3
##
## [[3]]
## [1] "Sun"
##
## [[4]]
## [1] "Mon"
Exercise
- Create a list that include 2 books, each book will be described by their title, authors (enter them as a vector of characters), number of pages, and a logical value that tells if you read it already or not. Name each members of lists, so that you can retrieve easily the information you are looking for.
- Search for the authors of your second book
- Edit the list to indicate that you have read your first book and not the second book
Show the answer
#Q1
mybooks <- list( book1 = list(title = "Advanced R", authors = c("Hadley Wickham"), pages = 200, readit=FALSE),
book2 = list(title = "Advanced R Solutions", authors = c("Malte Grosser","Henning Bumann","Hadley Wickham"), pages=300, readit=FALSE))
#Q2
mybooks$book2$authors
## [1] "Malte Grosser" "Henning Bumann" "Hadley Wickham"
#Alternative to Q2
mybooks[[2]][[2]]
## [1] "Malte Grosser" "Henning Bumann" "Hadley Wickham"
# Q3
mybooks$book2$readit <- TRUE