Skip to content

R - Lists

Lists are one of R’s most versatile data structures. Unlike atomic vectors, which must contain elements of the same type, lists can hold elements of different types. This makes them perfect for storing heterogeneous collections of objects, such as model parameters, configuration settings, or results from a complex analysis.

A list can contain numbers, strings, vectors, data frames, and even other lists.

You create a list using the list() function. It’s a best practice to name the elements of your list for clarity and easier access.

# Create a named list with various data types
project_config <- list(
project_name = "Global Sales Analysis",
analyst_id = 101,
regions = c("NA", "EU", "APAC"),
is_active = TRUE,
parameters = list(alpha = 0.05, beta = 0.9)
)
# Print the list to see its structure
print(project_config)

When we execute the above code, it produces a well-structured output:

$project_name
[1] "Global Sales Analysis"
$analyst_id
[1] 101
$regions
[1] "NA" "EU" "APAC"
$is_active
[1] TRUE
$parameters
$parameters$alpha
[1] 0.05
$parameters$beta
[1] 0.9

Accessing List Elements: The Three Key Operators

Section titled “Accessing List Elements: The Three Key Operators”

Understanding how to access list elements is crucial. R has three main operators for this, and they behave differently:

  • $ (The Dollar Sign): The most common and convenient way to access a named element. It extracts the element’s content directly.
  • [[...]] (Double Square Brackets): Extracts a single element’s content. You can use it with a name (e.g., my_list[["name"]]) or an index (e.g., my_list[[1]]).
  • [...] (Single Square Brackets): Subsets the list, but always returns another list. Useful for selecting multiple elements at once.
# Using the `$` operator to get the project name (returns a string)
name <- project_config$project_name
print(name)
# [1] "Global Sales Analysis"
# Using `[[...]]` to get the regions vector (returns a vector)
regions_vector <- project_config[["regions"]]
print(regions_vector)
# [1] "NA" "EU" "APAC"
# Using `[...]` to get a sub-list (returns a list)
sub_list <- project_config[1:2]
print(sub_list)
# $project_name
# [1] "Global Sales Analysis"
#
# $analyst_id
# [1] 101

Common Mistake: A frequent error for beginners is using [] when they want the content, resulting in a list instead of the expected value, which can cause downstream errors in functions.

Lists are mutable, meaning you can easily add, update, or delete elements.

# --- Update an element ---
project_config$is_active <- FALSE
# --- Add a new element ---
project_config$last_updated <- Sys.Date()
# --- Remove an element by setting it to NULL ---
project_config$analyst_id <- NULL
# Print the modified list
str(project_config) # str() gives a compact summary

The str() output shows our changes:

List of 5
$ project_name: chr "Global Sales Analysis"
$ regions : chr [1:3] "NA" "EU" "APAC"
$ is_active : logi FALSE
$ parameters :List of 2
..$ alpha: num 0.05
..$ beta : num 0.9
$ last_updated: Date, format: "YYYY-MM-DD"

While for loops can iterate over lists, a more modern, functional, and often cleaner approach is to use the map() family of functions from the purrr package (part of the tidyverse).

library(purrr)
list_of_numbers <- list(a = 1:5, b = 6:10, c = 11:15)
# Use map() to apply a function to each element.
# The result is always a list.
list_of_means <- map(list_of_numbers, mean)
print(list_of_means)
# Use map_dbl() to do the same, but return a numeric vector.
vector_of_means <- map_dbl(list_of_numbers, mean)
print(vector_of_means)

Output of the purrr example:

$a
[1] 3
$b
[1] 8
$c
[1] 13
a b c
3 8 13

You can merge lists with the c() function. To convert a list into a single atomic vector, use unlist(), but be aware that it will coerce all elements to a common type (usually character).

# Merging two lists
list1 <- list(a = 1, b = 2)
list2 <- list(c = "hello", d = "world")
merged_list <- c(list1, list2)
# Result: list(a = 1, b = 2, c = "hello", d = "world")
# Converting a list to a vector with unlist()
v <- unlist(list1)
# Result: a numeric vector c(a = 1, b = 2)
# Unlisting a mixed-type list forces type coercion
mixed_vector <- unlist(merged_list)
# Result: a character vector c(a = "1", b = "2", c = "hello", d = "world")