$ sudo teach IT
РАЗДЕЛ 7 · УРОК 4

reduce: самый мощный метод массивов

reduce — это «свёртка» массива в одно значение. Звучит просто, но за этим скрывается невероятная мощь. Сумма, произведение, максимум, группировка, преобразование в объект — всё это reduce.

⏱ ~30 минут 🎓 Новичок → Средний 📦 JavaScript

🧠 Идея: сворачиваем массив в одно значение

Все методы, которые мы изучали раньше, работают «один к одному»: map из массива даёт массив той же длины, filter — массив меньшей длины. А reduce из всего массива делает одно значение. Любое: число, строку, объект, другой массив.

Аналогия: представьте снежный ком, который катится с горы и собирает снег. Снег — это элементы массива. Ком нарастает с каждым шагом — это аккумулятор. В конце у вас один большой ком — это результат reduce.

Синтаксис:

array.reduce(function(accumulator, currentValue) {
  return /* новое значение аккумулятора */;
}, initialValue);

Четыре участника:

  • accumulator (аккумулятор) — «бегущий итог», который накапливается с каждым шагом
  • currentValue (текущее значение) — элемент массива, который обрабатывается прямо сейчас
  • колбэк — функция, которая получает аккумулятор и текущий элемент, возвращает новый аккумулятор
  • initialValue (начальное значение) — с чего начинается аккумулятор

💡 Всегда указывайте initialValue! Без него reduce использует первый элемент как начальное значение аккумулятора — это работает, но может привести к неожиданным результатам, особенно с пустыми массивами или объектами.

👣 Как работает reduce: шаг за шагом

Разберём на простейшем примере — сумме чисел. Посмотрим, что происходит на каждой итерации:

const numbers = [1, 2, 3, 4, 5];

const sum = numbers.reduce((acc, cur) => acc + cur, 0);
console.log(sum); // → 15
Шаг accumulator (acc) currentValue (cur) acc + cur (новый acc)
Старт 0 (initialValue) — —
1 0 1 1
2 1 2 3
3 3 3 6
4 6 4 10
5 (финал) 10 5 15 ✓

Видите? На каждом шаге аккумулятор «вбирает» в себя следующий элемент. Это и есть «свёртка» — у вас было 5 чисел, а стало одно.

🛠️ Практические примеры

➕ Сумма и произведение

const nums = [2, 3, 4, 5];

// Сумма
const sum = nums.reduce((acc, n) => acc + n, 0);
console.log(sum); // → 14

// Произведение
const product = nums.reduce((acc, n) => acc * n, 1);
console.log(product); // → 120 (2*3*4*5)
// Заметьте: начальное значение для произведения — 1, а не 0!

🏆 Максимум и минимум

const temps = [12, 7, 25, 3, 18];

// Максимум
const max = temps.reduce((acc, cur) => cur > acc ? cur : acc, -Infinity);
console.log(max); // → 25

// Минимум
const min = temps.reduce((acc, cur) => cur < acc ? cur : acc, Infinity);
console.log(min); // → 3

// Или через Math.max / Math.min
const max2 = temps.reduce((acc, cur) => Math.max(acc, cur), -Infinity);
console.log(max2); // → 25

📂 Группировка по свойству

const people = [
  { name: "Алиса", city: "Москва" },
  { name: "Боб", city: "Питер" },
  { name: "Карл", city: "Москва" },
  { name: "Диана", city: "Казань" },
  { name: "Ева", city: "Питер" }
];

// Сгруппировать по городу
const byCity = people.reduce((acc, person) => {
  const city = person.city;
  // Если в аккумуляторе ещё нет этого города — создаём пустой массив
  if (!acc[city]) {
    acc[city] = [];
  }
  // Добавляем человека в группу его города
  acc[city].push(person.name);
  return acc;
}, {}); // Начальное значение — пустой объект

console.log(byCity);
// → {
//     "Москва": ["Алиса", "Карл"],
//     "Питер": ["Боб", "Ева"],
//     "Казань": ["Диана"]
//   }

🔄 Преобразование массива в объект

// Задача: превратить массив объектов в словарь по id
const users = [
  { id: 1, name: "Алиса" },
  { id: 2, name: "Боб" },
  { id: 3, name: "Карл" }
];

const usersById = users.reduce((acc, user) => {
  acc[user.id] = user;
  return acc;
}, {});

console.log(usersById);
// → { 1: { id: 1, name: "Алиса" }, 2: {...}, 3: {...} }

// Теперь быстрый доступ по id
console.log(usersById[2].name); // → "Боб"
// Это в разы быстрее, чем каждый раз делать find!

🎯 reduce = map + filter + любой результат. Технически через reduce можно реализовать любой другой метод массива. Он — самый универсальный. Но это не значит, что всегда нужно использовать именно его: map и filter читаются понятнее. Используйте reduce, когда нужен нестандартный результат.

🛒 Реальный кейс: подсчёт стоимости корзины

const cart = [
  { name: "Ноутбук", price: 80000, qty: 1 },
  { name: "Мышь", price: 1500, qty: 2 },
  { name: "Клавиатура", price: 3000, qty: 1 },
  { name: "Наушники", price: 8000, qty: 1 }
];

// Подсчёт общей суммы
const total = cart.reduce((acc, item) => {
  return acc + item.price * item.qty;
}, 0);

console.log(`Итого: ${total.toLocaleString()} ₽`);
// → "Итого: 92 500 ₽"

// Количество позиций (штук)
const totalQty = cart.reduce((acc, item) => acc + item.qty, 0);
console.log(`Товаров: ${totalQty} шт.`); // → "Товаров: 5 шт."

// Самый дорогой товар
const mostExpensive = cart.reduce((acc, item) => {
  return item.price > acc.price ? item : acc;
}, cart[0]);

console.log(`Самый дорогой: ${mostExpensive.name}`);
// → "Самый дорогой: Ноутбук"

✅ Итоги урока

  • reduce(callback, initialValue) — «сворачивает» массив в одно значение любого типа
  • Колбэк получает accumulator (накопленный итог) и currentValue (текущий элемент)
  • Что вернул колбэк — то становится новым аккумулятором на следующем шаге
  • Всегда указывайте initialValue — это делает код предсказуемым
  • Начальное значение зависит от задачи: для суммы — 0, для произведения — 1, для объекта — {}, для массива — []
  • reduce умеет группировать, преобразовывать в объект, искать максимум/минимум
  • Технически через reduce можно реализовать любой другой метод массивов

В следующем уроке — sort() с компаратором: почему массив чисел сортируется «неправильно» по умолчанию и как это исправить. 🔢

reduce — свёртка массива

6 вопросов

Подсчёт голосов через reduce

Дан массив строк с голосами: ['да', 'нет', 'да', 'воздержался', 'да', 'нет']. Используя reduce, подсчитайте количество каждого варианта. Верните объект вида { 'да': 3, 'нет': 2, 'воздержался': 1 }.

Нахождение самого дорогого товара через reduce

Дан массив товаров с полями { name, price }. Используя reduce, найдите товар с максимальной ценой. Если массив пустой, верните null.