← Назад к вопросам

Для чего используется метод Reduce?

1.3 Junior🔥 221 комментариев
#Node.js и JavaScript

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI28 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Использование метода Reduce

Reduce — это высокоуровневая функция обработки массивов в JavaScript/TypeScript, которая комбинирует все элементы массива в одно значение, применяя функцию-аккумулятор ко каждому элементу последовательно.

Основное назначение Reduce

  1. Агрегирование данных — суммирование, подсчёт, объединение элементов
  2. Трансформация структур — преобразование массива в объект, строку или другую структуру
  3. Фильтрация и маппирование одновременно — комбинирование нескольких операций в одну итерацию
  4. Построение сложных структур — индексирование, группировка, статистика

Синтаксис

array.reduce(
  (accumulator, currentValue, index, array) => {
    // accumulator — результат из предыдущей итерации
    // currentValue — текущий элемент массива
    // index — индекс текущего элемента (опционально)
    // array — исходный массив (опционально)
    return updatedAccumulator;
  },
  initialValue  // Начальное значение (опционально)
);

Примеры использования

1. Суммирование элементов

const numbers = [10, 20, 30, 40];

const sum = numbers.reduce((acc, num) => acc + num, 0);
console.log(sum);  // 100

// Пошагово:
// Итерация 1: acc=0, num=10 → 10
// Итерация 2: acc=10, num=20 → 30
// Итерация 3: acc=30, num=30 → 60
// Итерация 4: acc=60, num=40 → 100

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

const users = [
  { id: 1, name: 'Alice' },
  { id: 2, name: 'Bob' },
  { id: 3, name: 'Charlie' }
];

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

console.log(usersMap);
// { 1: { id: 1, name: 'Alice' }, 2: { id: 2, name: 'Bob' }, ... }

3. Группировка элементов по категориям

const items = [
  { name: 'Apple', category: 'fruit' },
  { name: 'Broccoli', category: 'vegetable' },
  { name: 'Banana', category: 'fruit' },
  { name: 'Carrot', category: 'vegetable' }
];

const grouped = items.reduce((acc, item) => {
  if (!acc[item.category]) {
    acc[item.category] = [];
  }
  acc[item.category].push(item.name);
  return acc;
}, {});

console.log(grouped);
// {
//   fruit: ['Apple', 'Banana'],
//   vegetable: ['Broccoli', 'Carrot']
// }

4. Подсчёт частоты элементов

const words = ['cat', 'dog', 'cat', 'bird', 'dog', 'cat'];

const frequency = words.reduce((acc, word) => {
  acc[word] = (acc[word] || 0) + 1;
  return acc;
}, {});

console.log(frequency);
// { cat: 3, dog: 2, bird: 1 }

5. Вычисление статистики

const scores = [85, 92, 78, 95, 88];

const stats = scores.reduce(
  (acc, score) => ({
    sum: acc.sum + score,
    count: acc.count + 1,
    min: Math.min(acc.min, score),
    max: Math.max(acc.max, score)
  }),
  { sum: 0, count: 0, min: Infinity, max: -Infinity }
);

const average = stats.sum / stats.count;
console.log({ average, min: stats.min, max: stats.max });
// { average: 87.6, min: 78, max: 95 }

6. Склеивание (Flatten) вложенных массивов

const nested = [[1, 2], [3, 4], [5, 6]];

const flat = nested.reduce(
  (acc, arr) => acc.concat(arr),
  []
);

console.log(flat);  // [1, 2, 3, 4, 5, 6]

7. Цепь преобразований (Compose)

const value = 5;

const transformers = [
  (x: number) => x * 2,      // 5 * 2 = 10
  (x: number) => x + 3,      // 10 + 3 = 13
  (x: number) => x / 2       // 13 / 2 = 6.5
];

const result = transformers.reduce(
  (acc, fn) => fn(acc),
  value
);

console.log(result);  // 6.5

Reduce vs Map/Filter/ForEach

Когда использовать Reduce:

const data = [
  { name: 'Product A', price: 100, quantity: 2 },
  { name: 'Product B', price: 50, quantity: 3 }
];

// ❌ Несколько проходов (менее эффективно)
const total = data
  .map(p => p.price * p.quantity)
  .filter(p => p > 100)
  .reduce((sum, price) => sum + price, 0);

// ✅ Один проход (более эффективно)
const total = data.reduce((acc, item) => {
  const itemTotal = item.price * item.quantity;
  return itemTotal > 100 ? acc + itemTotal : acc;
}, 0);

Практические примеры в Node.js

Обработка логов

const logs = [
  { level: 'info', timestamp: '10:00', message: 'App started' },
  { level: 'error', timestamp: '10:05', message: 'Connection failed' },
  { level: 'info', timestamp: '10:06', message: 'Reconnected' },
  { level: 'error', timestamp: '10:07', message: 'Timeout' }
];

const summary = logs.reduce((acc, log) => {
  if (!acc[log.level]) {
    acc[log.level] = [];
  }
  acc[log.level].push(log.message);
  return acc;
}, {});

console.log(summary);
// {
//   info: ['App started', 'Reconnected'],
//   error: ['Connection failed', 'Timeout']
// }

Вычисление суммы заказов

const orders = [
  { id: 1, items: [{price: 30}, {price: 50}] },
  { id: 2, items: [{price: 25}, {price: 40}, {price: 35}] }
];

const totalRevenue = orders.reduce((total, order) => {
  const orderSum = order.items.reduce((sum, item) => sum + item.price, 0);
  return total + orderSum;
}, 0);

console.log(totalRevenue);  // 180

Важные моменты

1. Нужно вернуть аккумулятор

// ❌ Неправильно: забыли return
const result = numbers.reduce((acc, num) => {
  acc += num;
  // missing return!
});

// ✅ Правильно
const result = numbers.reduce((acc, num) => {
  return acc + num;
}, 0);

// ✅ Или со стрелкой одной строкой
const result = numbers.reduce((acc, num) => acc + num, 0);

2. Всегда указывайте начальное значение

const nums = [1, 2, 3];

// ❌ Может быть неправильно если массив пустой
const sum = nums.reduce((a, b) => a + b);  // undefined если массив пустой

// ✅ Правильно
const sum = nums.reduce((a, b) => a + b, 0);  // 0 если массив пустой

Производительность

Reduce проходит массив один раз — O(n) сложность. Это эффективнее чем цепочка map → filter → reduce которая имеет O(3n):

const arr = Array.from({length: 1000000}, (_, i) => i);

// Медленнее: три прохода
const result1 = arr
  .map(x => x * 2)
  .filter(x => x > 500)
  .reduce((a, b) => a + b, 0);

// Быстрее: один проход
const result2 = arr.reduce((acc, x) => {
  if (x * 2 > 500) {
    return acc + (x * 2);
  }
  return acc;
}, 0);

Вывод

Reduce — это мощный инструмент функционального программирования:

  • Универсален — преобразует массивы в любую структуру
  • Эффективен — один проход по данным
  • Функциональный стиль — декларативный код без побочных эффектов
  • Готов к работе с сложными структурами — группировка, статистика, индексирование

Это один из ключевых методов, который каждый Node.js разработчик должен освоить для написания чистого и эффективного кода.