# Let's create a list of data structures:
obj1 <- list("a", list(1, elt = "foo"))
obj2 <- list("b", list(2, elt = "bar"))
x <- list(obj1, obj2)
# pluck() provides a way of retrieving objects from such data
# structures using a combination of numeric positions, vector or
# list names, and accessor functions.
# Numeric positions index into the list by position, just like `[[`:
pluck(x, 1)
x[[1]]
pluck(x, 1, 2)
x[[1]][[2]]
# Supply names to index into named vectors:
pluck(x, 1, 2, "elt")
x[[1]][[2]][["elt"]]
# By default, pluck() consistently returns `NULL` when an element
# does not exist:
pluck(x, 10)
try(x[[10]])
# You can also supply a default value for non-existing elements:
pluck(x, 10, .default = NA)
# If you prefer to consistently fail for non-existing elements, use
# the opinionated variant chuck():
chuck(x, 1)
try(chuck(x, 10))
try(chuck(x, 1, 10))
# The map() functions use pluck() by default to retrieve multiple
# values from a list:
map(x, 2)
# Pass multiple indexes with a list:
map(x, list(2, "elt"))
# This is equivalent to:
map(x, pluck, 2, "elt")
# You can also supply a default:
map(x, list(2, "elt", 10), .default = "superb default")
# Or use the strict variant:
try(map(x, chuck, 2, "elt", 10))
# You can also assign a value in a pluck location with pluck<-:
pluck(x, 2, 2, "elt") <- "quuux"
x
# This is a shortcut for the prefix function assign_in():
y <- assign_in(x, list(2, 2, "elt"), value = "QUUUX")
y
# pluck() also supports accessor functions:
my_element <- function(x) x[[2]]$elt
# The accessor can then be passed to pluck:
pluck(x, 1, my_element)
pluck(x, 2, my_element)
# Even for this simple data structure, this is more readable than
# the alternative form because it requires you to read both from
# right-to-left and from left-to-right in different parts of the
# expression:
my_element(x[[1]])
# If you have a list of accessors, you can splice those in with `!!!`:
idx <- list(1, my_element)
pluck(x, !!!idx)
Run the code above in your browser using DataLab