reduce(), accumulate() и walk()
Сворачивайте списки, создавайте накопительные результаты и применяйте побочные эффекты с помощью walk().
«reduce(), accumulate() и walk()» — бесплатный урок R Academy на CoddyKit. Это урок 3 из 4. Ты можешь прочитать весь урок бесплатно ниже — а потом практиковать его прямо в браузере с встроенным редактором кода и ИИ-репетитором 24/7. Это часть пути обучения R Academy, и твой прогресс синхронизируется между веб-версией и приложением CoddyKit. Курс R Academy содержит 4 уроков всего.
За пределами map() — другие функции purrr
Функция map() применяет функцию независимо к каждому элементу, но для некоторых задач требуется объединять элементы (reduce), накапливать промежуточные результаты или применять функции исключительно ради побочных эффектов (walk). В purrr для каждого такого случая предусмотрены отдельные функции.
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() — свёртка списка в одно значение
reduce(.x, .f, .init) последовательно применяет .f к элементам .x слева направо, сворачивая список в одно значение. reduce(list(a,b,c), f) вычисляет 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() с .init
Аргумент .init задаёт начальное значение (seed). Первый вызов имеет вид f(.init, x[1]). Это особенно важно, если список может быть пустым (результатом будет .init) или если требуется определённое начальное состояние.
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() с датафреймами — последовательное объединение
Одно из самых мощных применений reduce() — объединение списка датафреймов. Вместо записи left_join(left_join(df1, df2), df3) используйте 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() — сохранение промежуточных результатов
accumulate(.x, .f) похожа на reduce(), но сохраняет все промежуточные значения. Функция возвращает вектор (или список) той же длины, что и входные данные, показывая накопленный результат после каждого шага.
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() для пошаговых результатов
accumulate() особенно полезна для отслеживания шагов алгоритма, посимвольного построения строк и любых процессов, в которых нужно просматривать каждое промежуточное состояние, а не только итоговый результат.
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() — побочные эффекты без возвращаемого результата
walk(.x, .f) применяет .f к каждому элементу .x исключительно ради побочных эффектов (вывода, записи файлов, отправки сообщений). Функция неявно возвращает .x, поэтому её можно использовать в конвейере, не разрывая цепочку.
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() в конвейере
Поскольку walk() неявно возвращает .x, её можно вставить в конвейер dplyr, чтобы записывать в журнал или выводить промежуточные результаты, не нарушая последовательность операций. Представляйте её как точку подключения для отладки или ведения журнала.
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() — побочные эффекты с двумя входными наборами
walk2(.x, .y, .f) — версия walk() для двух входных наборов. Классический пример: запись нескольких датафреймов в файлы, где .x — список датафреймов, а .y — список путей к файлам.
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() — обход с индексом
iwalk(.x, .f) похожа на walk(), но передаёт имя элемента (или индекс) вторым аргументом .y. Это удобно, когда в побочном эффекте нужно знать, какой именно элемент обрабатывается.
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() — свёртка справа налево
reduce(.x, .f, .dir='backward') (или устаревшая reduce_right()) применяет функцию справа налево: f(a, f(b, f(c, d))). Это важно для некоммутативных операций, например вычитания или построения строк.
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))Быстрая проверка
Когда следует использовать walk() вместо map()?
Итоги: reduce, accumulate, walk
Главные выводы о reduce, accumulate и walk:
reduce(.x, .f)— сворачивает список в одно значение (слева направо);.initзадаёт начальное значениеreduce(list_of_dfs, left_join)— мощный шаблон для последовательного объединения датафреймовaccumulate(.x, .f)— похожа на reduce, но возвращает все промежуточные результатыwalk(.x, .f)— применяется ради побочных эффектов (вывод, запись, ведение журнала); возвращает.xwalk2(.x, .y, .f)— walk для двух входных наборов (например, датафрейм и путь к файлу)iwalk(.x, .f)— обход с именем элемента в качестве второго аргумента
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'))Изучай R с ИИ-репетитором — бесплатно
Пиши и запускай код прямо в браузере, получай мгновенную помощь от ИИ-репетитора 24/7 и продолжи учиться на сайте или в приложении.
- Курсы
- 43
- Уроки
- 159
Часто задаваемые вопросы
Урок «reduce(), accumulate() и walk()» бесплатный?
Да — полный текст урока «reduce(), accumulate() и walk()» бесплатно доступен здесь в веб-версии. Чтобы практиковать его интерактивно (встроенный редактор кода и ИИ-репетитор 24/7) и разблокировать остальной курс R Academy, подпишись на CoddyKit PRO. Курс R Academy содержит 4 уроков всего.
Чему я научусь в уроке «reduce(), accumulate() и walk()»?
Сворачивайте списки, создавайте накопительные результаты и применяйте побочные эффекты с помощью walk(). Ты практикуешь R Academy с помощью реального кода, который запускаешь прямо в браузере, и ИИ-репетитор 24/7 отвечает на твои вопросы во время урока.
Нужен ли мне опыт, чтобы начать R Academy?
Предыдущий опыт не требуется. R Academy на CoddyKit структурирован для всех уровней — от новичков до продвинутых, поэтому ты можешь начать отсюда или с самого начала и учиться в своем темпе. Это урок 3 из 4.
Сколько времени занимает урок «reduce(), accumulate() и walk()»?
Большинство уроков CoddyKit занимают около 5–10 минут. Каждый из них компактный и интерактивный, поэтому ты постоянно делаешь прогресс и продолжаешь с того же места в веб-версии и приложении.
Можно ли писать и запускать код в этом уроке R Academy?
Да. Каждый урок R Academy включает встроенный редактор кода, поэтому ты пишешь и запускаешь реальный код прямо в браузере и получаешь моментальную обратную связь от AI — локальная установка не требуется.
Все уроки этого курса
- map() и типизированные варианты
- map2() и pmap() для нескольких входных данных
- reduce(), accumulate() и walk()
- keep(), discard() и фильтрация списков