purrr is mainly used for functional programme, especially making it easier and more consistent to apply a function over a group of items and collect the output:
mpg cyl disp hp drat wt qsec
"Loads" "Not much" "Loads" "Loads" "Not much" "Not much" "Loads"
vs am gear carb
"Not much" "Not much" "Not much" "Not much"
But purrr also has a set of tools for working with lists. This session is an introduction to those functions. We’ll use the purrr cheatsheet as a starting point for this session.
A reminder about lists
Lists are a data structure in R with two very useful properties. Unlike vectors, they can contain data of different classes. Unlike data frames/tibbles, they can be ragged, containing items of different lengths:
test_list<-list(a =LETTERS, b =NA, c =1:5, d =NULL, e =letters)test_list
$a
[1] "A" "B" "C" "D" "E" "F" "G" "H" "I" "J" "K" "L" "M" "N" "O" "P" "Q" "R" "S"
[20] "T" "U" "V" "W" "X" "Y" "Z"
$b
[1] NA
$c
[1] 1 2 3 4 5
$d
NULL
$e
[1] "a" "b" "c" "d" "e" "f" "g" "h" "i" "j" "k" "l" "m" "n" "o" "p" "q" "r" "s"
[20] "t" "u" "v" "w" "x" "y" "z"
subset a list by item/index with []:
test_list["c"]
$c
[1] 1 2 3 4 5
test_list[1]
$a
[1] "A" "B" "C" "D" "E" "F" "G" "H" "I" "J" "K" "L" "M" "N" "O" "P" "Q" "R" "S"
[20] "T" "U" "V" "W" "X" "Y" "Z"
** retrieve the contents of a list item with $ or [[]]:
test_list[["c"]]
[1] 1 2 3 4 5
test_list$a
[1] "A" "B" "C" "D" "E" "F" "G" "H" "I" "J" "K" "L" "M" "N" "O" "P" "Q" "R" "S"
[20] "T" "U" "V" "W" "X" "Y" "Z"
** subset those list contents with chained square brackets:
test_list[["a"]][2]
[1] "B"
test_list$c[3]
[1] 3
modify()
Effectively map for list items. modify() applies a function to each list item and returns a structurally-identical modified list:
test_list|>modify_at("e", toupper)# select list item by quoted name
$a
[1] "A" "B" "C" "D" "E" "F" "G" "H" "I" "J" "K" "L" "M" "N" "O" "P" "Q" "R" "S"
[20] "T" "U" "V" "W" "X" "Y" "Z"
$b
[1] NA
$c
[1] 1 2 3 4 5
$d
NULL
$e
[1] "A" "B" "C" "D" "E" "F" "G" "H" "I" "J" "K" "L" "M" "N" "O" "P" "Q" "R" "S"
[20] "T" "U" "V" "W" "X" "Y" "Z"
test_list|>modify_if(is.numeric, \(x)x+2)# select list item by function
$a
[1] "A" "B" "C" "D" "E" "F" "G" "H" "I" "J" "K" "L" "M" "N" "O" "P" "Q" "R" "S"
[20] "T" "U" "V" "W" "X" "Y" "Z"
$b
[1] NA
$c
[1] 3 4 5 6 7
$d
NULL
$e
[1] "a" "b" "c" "d" "e" "f" "g" "h" "i" "j" "k" "l" "m" "n" "o" "p" "q" "r" "s"
[20] "t" "u" "v" "w" "x" "y" "z"
list(list(list(list(deepo =c(3, 4, 5)))))|># likely to be more trouble than it's worth, especially because many functions will do odd things to list itemsmodify_depth(4, \(x)x*10)
A bit like cumsum()! Apply a function to each element recursively.
1:10|>reduce(sum)# so think 1+2=3, then 3+3=6, then 6+4=10,...,45+10=55. That can be a bit hard to understand, so accumulate helps by showing intermediate results