Группировка и суммирование значений в массиве объектов

Пройдите тест, узнайте какой профессии подходите

Я предпочитаю
0%
Работать самостоятельно и не зависеть от других
Работать в команде и рассчитывать на помощь коллег
Организовывать и контролировать процесс работы

Быстрый ответ

Для группировки объектов по определённому свойству великолепно подходит метод Array.prototype.reduce() — это наилучший выбор:

JS
Скопировать код
const groupBy = (arr, prop) => arr.reduce((acc, item) => {
  (acc[item[prop]] = acc[item[prop]] || []).push(item);
  return acc;
}, {});

// Проиллюстрируем применение этой функции на примере.
const result = groupBy([{id: 1, val: 'A'}, {id: 1, val: 'B'}, {id: 2, val: 'C'}], 'id');

На выходе мы получаем удобную для поиска структуру, где ключами являются значения свойства id, а значениями – массивы соответствующих объектов.

Кинга Идем в IT: пошаговый план для смены профессии

Ускорение работы с помощью цикла 'for'

Если вы работаете с большим объёмом данных и производительность для вас имеет значение, выбирайте цикл for:

JS
Скопировать код
const groupByForLoop = (arr, prop) => {
  const grouped = {};
  for (let i = 0; i < arr.length; i++) {
    let key = arr[i][prop];
    if (!grouped[key]) grouped[key] = [];
    grouped[key].push(arr[i]);
  }
  return grouped;
};

Цикл for помогает избежать ненужных затрат на вызовы функций и достигнуть высокой скорости исполнения.

Добавляем гибкость с помощью ES6 Map

Когда важен порядок элементов и требуется гибкость, вам может пригодиться структура данных Map из ES6:

JS
Скопировать код
const groupByMap = (arr, prop) => {
  return arr.reduce((acc, item) => {
    const key = item[prop];
    const collection = acc.get(key) || [];
    acc.set(key, [...collection, item]);
    return acc;
  }, new Map());
};

Использование Map обеспечивает сохранение порядка элементов, что может быть критичным для некоторых задач.

Группировка в сочетании с суммированием

Если вам требуется осуществить группировку и одновременно суммировать значения, это можно выполнить за один проход:

JS
Скопировать код
const groupBySum = (arr, groupProp, sumProp) => {
  return arr.reduce((acc, item) => {
    let key = item[groupProp];
    let val = item[sumProp];
    acc[key] = (acc[key] || 0) + val;
    return acc;
  }, {});
};

Такой подход позволяет включить операцию суммирования непосредственно в процесс группировки, снижая общее количество проходов по массиву.

TypeScript: Долгой живи типовая безопасность

Для тех, кому ближе TypeScript, добавление типовой безопасности к функциям группировки будет неоценимым:

typescript
Скопировать код
function groupBy<T, K extends keyof T>(arr: T[], prop: K): Record<T[K], T[]> {
  return arr.reduce((acc: Record<T[K], T[]>, item: T) => {
    const groupKey = item[prop];
    if (!acc[groupKey]) acc[groupKey] = [];
    acc[groupKey].push(item);
    return acc;
  }, {} as Record<T[K], T[]>);
}

// Пример применения типов в TypeScript:
const result = groupBy([{id: 1, value: 'A'}, {id: 1, value: 'B'}, {id: 2, value: 'C'}], 'id');

В TypeScript применение строгой типизации повышает безопасность кода и предотвращает возникновение ошибок типизации.

Визуализация

Продемонстрируем процесс группировки на наглядном примере:

Markdown
Скопировать код
Представьте себе сад 🌳, полный разнообразных фруктов.

Каждому виду фруктов соответствует своя корзина:

Яблоки: 🍎🍎🍎 → [Корзина🧺]
Бананы: 🍌🍌 → [Корзина🧺]
Вишня: 🍒🍒🍒🍒 → [Корзина🧺]

Вот как работает функция groupby:

JS
Скопировать код
const fruitBasket = groupBy(fruits, fruit => fruit.type);
// В итоге, у нас получаются корзины, аккуратно наполненные 🍎, 🍌 и 🍒!

Функция Groupby позволяет эффективно организовывать объекты по общим характеристикам.

Решение задачи: больше примеров использования

Гибкость критериев группировки

Предположим, вам нужно адаптировать критерии группировки. Это можно сделать без особых сложностей:

JS
Скопировать код
const groupByFunction = (arr, fn) => arr.reduce((acc, item) => {
  const key = fn(item);
  (acc[key] = acc[key] || []).push(item);
  return acc;
}, {});

// Пример использования: группировка гораздо шире, чем просто сортировка по свойству...
const groupedByCustomLogic = groupByFunction(objects, (obj) => obj.date.getFullYear());

Этот вариант groupBy позволяет применять любую функцию для расчета ключей группировки.

Погружение во вложенные свойства

Если вложенные свойства вызывают у вас беспокойство, прорывайтесь в их глубины следующим образом:

JS
Скопировать код
const groupByDeep = (arr, propPath) => {
  return arr.reduce((acc, item) => {
    const keys = propPath.split('.');
    const key = keys.reduce((o, k) => (o || {})[k], item);
    (acc[key] = acc[key] || []).push(item);
    return acc;
  }, {});
};

Таким образом, можно осуществлять группировку элементов, учитывая свойства на разных уровнях вложенности.

Полезные материалы

  1. Документация по методу reduce() на MDN — подробно изучите тонкости метода reduce().
  2. Обсуждение методов группировки объектов на основе массива на Stack Overflow — здесь представлено множество примеров группировки.
  3. Документация Lodash — ознакомьтесь с функцией groupBy() в Lodash для более сложных операций.
  4. Документация по методу map() на MDN — овлейте все возможности метода map().
  5. Документация по методу filter() на MDN — изучите детали применения метода filter().
  6. Документация по методу sort() на MDN — глубокое погружение в тело сортировки массивов.