reduce(), accumulate(), and walk()
Fold lists, build cumulative results, and apply side-effects with walk().
reduce(), accumulate(), and walk() is a free R Academy lesson on CoddyKit — lesson 3 of 4. You can read the complete lesson below for free — then practise it hands-on in the browser with a built-in code editor and a 24/7 AI tutor. It is part of the R Academy learning path, one of 4 lessons in the course, and your progress syncs across the web and the CoddyKit app.
Beyond map() — Other purrr Verbs
While map() applies a function independently to each element, some tasks require operations that combine elements (reduce), accumulate intermediate results, or apply functions purely for side effects (walk). purrr provides dedicated functions for each case.
library(purrr)
# Example: combining a list of numbers into a single value
nums <- list(1, 2, 3, 4, 5)
# We want: 1 + 2 + 3 + 4 + 5 = 15
# map() can't do this — it returns 5 separate results
# reduce() folds the list into one value
result <- reduce(nums, `+`)
cat('Sum via reduce:', result)reduce() — Fold a List to One Value
reduce(.x, .f, .init) applies .f cumulatively to elements of .x, from left to right, reducing the list to a single value. reduce(list(a,b,c), f) computes f(f(a,b),c).
library(purrr)
# reduce with max: find the overall maximum
values <- list(42, 17, 89, 55, 23)
result <- reduce(values, max)
cat('Maximum:', result, '\n')
# reduce with paste: concatenate strings
words <- list('The', 'quick', 'brown', 'fox')
reduce(words, paste)reduce() with .init
The .init argument provides a starting (seed) value. The first call becomes f(.init, x[1]). This is essential when the list might be empty (reduces to .init) or when you need a specific starting state.
library(purrr)
# Running count of elements matching a condition
data <- list(5, 12, 3, 18, 7, 15, 2)
# Count values greater than 10, starting from 0
reduce(data, function(count, x) count + (x > 10), .init = 0L)
# Also useful for string building:
reduce(c('A','B','C'), paste, sep='-', .init='START')reduce() with Data Frames — Chaining Joins
One of the most powerful uses of reduce(): joining a list of data frames. Instead of writing left_join(left_join(df1, df2), df3), use reduce(list_of_dfs, left_join, by='key').
library(purrr)
library(dplyr)
base_df <- data.frame(id=1:3, name=c('Alice','Bob','Carol'))
scores <- data.frame(id=1:3, score=c(85,90,78))
grades <- data.frame(id=1:3, grade=c('B','A','C'))
city <- data.frame(id=1:3, city=c('NYC','LA','Chicago'))
dfs <- list(base_df, scores, grades, city)
reduce(dfs, left_join, by='id')accumulate() — Keep Intermediate Results
accumulate(.x, .f) is like reduce() but keeps all intermediate values. It returns a vector (or list) of the same length as the input, showing the running result after each step.
library(purrr)
# Running sum — same as cumsum() but via accumulate
values <- c(100, 120, 95, 140, 160)
accumulate(values, `+`)
# Running maximum
accumulate(c(50, 52, 48, 55, 53, 58), max)accumulate() for Step-by-Step Results
accumulate() is especially useful for tracing algorithm steps, building strings character-by-character, or any process where you want to inspect every intermediate state, not just the final result.
library(purrr)
# Compound interest step by step
principal <- 1000
rates <- c(0.05, 0.05, 0.05, 0.05, 0.05) # 5% per year
accumulate(rates, function(balance, rate) {
round(balance * (1 + rate), 2)
}, .init = principal)walk() — Side Effects Without Return
walk(.x, .f) applies .f to each element of .x purely for its side effects (printing, writing files, sending messages). It invisibly returns .x, so you can use it in a pipeline without breaking the chain.
library(purrr)
# Print a summary for each dataset
datasets <- list(
mtcars = mtcars[,1:3],
iris = iris[,1:3]
)
walk(datasets, function(df) {
cat('Rows:', nrow(df), '| Cols:', ncol(df),
'| NAs:', sum(is.na(df)), '\n')
})walk() in a Pipeline
Because walk() returns .x invisibly, you can insert it into a dplyr pipeline to log or print intermediate results without breaking the flow. Think of it as a debugging or logging tap.
library(purrr)
library(dplyr)
results <- list(
East = data.frame(rep=c('A','B'), sales=c(100,120)),
West = data.frame(rep=c('C','D'), sales=c(200,190))
)
# Log each region's data, then continue processing
region_totals <- results %>%
walk(~cat('Processing:', nrow(.x), 'rows\n')) %>%
map_dbl(~sum(.x$sales))
print(region_totals)walk2() — Side Effects with Two Inputs
walk2(.x, .y, .f) is the two-input version of walk(). A classic use case: write multiple data frames to files, where .x is the list of data frames and .y is the list of file paths.
library(purrr)
data_list <- list(
east = data.frame(x=1:3, y=4:6),
west = data.frame(x=7:9, y=10:12)
)
file_paths <- list(
'/tmp/east_data.csv',
'/tmp/west_data.csv'
)
# Write each data frame to its corresponding path
walk2(data_list, file_paths, function(df, path) {
write.csv(df, path, row.names=FALSE)
cat('Written:', path, '\n')
})iwalk() — Walk with Index
iwalk(.x, .f) is like walk() but passes the element name (or index) as the second argument .y. This is convenient when you need to know which element you're processing in the side effect.
library(purrr)
region_counts <- list(East=150, West=200, North=85, South=120)
# Print each region with its rank
iwalk(region_counts, function(count, name) {
cat(name, ':', count, 'customers\n')
})reduce_right() — Right-to-Left Reduction
reduce(.x, .f, .dir='backward') (or the deprecated reduce_right()) applies the function from right to left: f(a, f(b, f(c, d))). This matters for non-commutative operations like subtraction or string building.
library(purrr)
words <- c('fox','brown','quick','The')
# Left-to-right: 'The quick brown fox'
reduce(rev(words), paste)
# Right-to-left: same effect but starting from right
reduce(words, function(a, b) paste(b, a))Quick Check
When would you use walk() instead of map()?
Recap: reduce, accumulate, walk
Key takeaways for reduce, accumulate, and walk:
reduce(.x, .f)— fold a list to one value (left to right);.initsets starting valuereduce(list_of_dfs, left_join)— powerful pattern for chaining joinsaccumulate(.x, .f)— like reduce but returns all intermediate resultswalk(.x, .f)— apply for side effects (print, write, log); returns.xwalk2(.x, .y, .f)— two-input walk (e.g., data frame + file path)iwalk(.x, .f)— walk with element name as second argument
library(purrr)
library(dplyr)
# reduce() joins a list of data frames, accumulate() shows interim states
monthly_sums <- c(100, 120, 95, 140, 160, 130)
cat('reduce (total): ', reduce(monthly_sums, `+`), '\n')
cat('accumulate (running):', accumulate(monthly_sums, `+`), '\n')
# walk() for side-effect logging
results <- list(a=42, b=17, c=89)
walk(results, ~cat('Value:', .x, '\n'))Frequently asked questions
Is the “reduce(), accumulate(), and walk()” lesson free?
Yes — the full text of “reduce(), accumulate(), and walk()” is free to read here on the web, and the R Academy course includes 4 lessons in total. To practise it interactively (a built-in code editor and a 24/7 AI tutor) and unlock the rest of the R Academy course, upgrade to CoddyKit PRO.
What will I learn in “reduce(), accumulate(), and walk()”?
Fold lists, build cumulative results, and apply side-effects with walk(). You practise R Academy with hands-on code you run directly in the browser, and a 24/7 AI tutor answers your questions as you work through the lesson.
Do I need any experience to start R Academy?
No prior experience is required. R Academy on CoddyKit is structured for beginners through advanced learners; this is — lesson 3 of 4, so you can start here or from the beginning and move at your own pace.
How long does the “reduce(), accumulate(), and walk()” lesson take?
Most CoddyKit lessons take about 5–10 minutes. Each one is bite-sized and interactive, so you make steady progress and pick up exactly where you left off across the web and the app.
Can I write and run code in this R Academy lesson?
Yes. Every R Academy lesson includes a built-in code editor, so you write and run real code right in your browser and get instant AI feedback — no local setup required.
All lessons in this course
- map() and Typed Variants
- map2() and pmap() for Multiple Inputs
- reduce(), accumulate(), and walk()
- keep(), discard(), and List Filtering