← Назад к вопросам
Группировка массива объектов по ключу
1.0 Junior🔥 251 комментариев
#React
Условие
Напишите функцию groupBy(arr, key), которая группирует массив объектов по значению указанного ключа.
Требования
- Функция принимает массив объектов и имя ключа для группировки
- Возвращает объект, где ключи - уникальные значения указанного поля
- Значения - массивы объектов с соответствующим значением ключа
- Временная сложность должна быть O(n)
Примеры
const people = [
{ name: "Alice", city: "Moscow" },
{ name: "Bob", city: "SPb" },
{ name: "Charlie", city: "Moscow" },
{ name: "Diana", city: "SPb" }
];
groupBy(people, "city");
// Результат:
// {
// "Moscow": [{ name: "Alice", city: "Moscow" }, { name: "Charlie", city: "Moscow" }],
// "SPb": [{ name: "Bob", city: "SPb" }, { name: "Diana", city: "SPb" }]
// }
Бонус
Добавьте поддержку функции вместо ключа: groupBy(arr, item => item.city).
Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI23 мар. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
Решение: Группировка массива объектов по ключу
Практическое применение
Группировка данных — один из самых часто используемых операций при обработке массивов. Она применяется при фильтрации по категориям, агрегировании статистики, организации данных для отображения. Эта функция работает за один проход массива с O(n) сложностью.
Базовое решение
function groupBy(arr, key) {
return arr.reduce((result, item) => {
const groupKey = item[key];
if (!result[groupKey]) {
result[groupKey] = [];
}
result[groupKey].push(item);
return result;
}, {});
}
Версия с поддержкой функции
function groupBy(arr, keyOrFn) {
return arr.reduce((result, item) => {
// Определяем функцию получения ключа
const getKey = typeof keyOrFn === 'function' ? keyOrFn : (obj) => obj[keyOrFn];
const groupKey = getKey(item);
if (!result[groupKey]) {
result[groupKey] = [];
}
result[groupKey].push(item);
return result;
}, {});
}
TypeScript версия
type GroupKey = string | number | symbol;
type GroupByFn<T> = (item: T) => GroupKey;
type GroupByKey<T> = keyof T;
type GroupBySelector<T> = GroupByKey<T> | GroupByFn<T>;
function groupBy<T extends Record<string, any>>(
arr: T[],
selector: GroupBySelector<T>
): Record<GroupKey, T[]> {
const getKey = typeof selector === 'function'
? selector as GroupByFn<T>
: (item: T) => item[selector as GroupByKey<T>];
return arr.reduce((result, item) => {
const groupKey = String(getKey(item));
if (!result[groupKey]) {
result[groupKey] = [];
}
result[groupKey].push(item);
return result;
}, {} as Record<GroupKey, T[]>);
}
Примеры использования
// Базовый пример с ключом
const people = [
{ name: "Alice", city: "Moscow" },
{ name: "Bob", city: "SPb" },
{ name: "Charlie", city: "Moscow" },
{ name: "Diana", city: "SPb" }
];
const byCity = groupBy(people, "city");
console.log(byCity);
// {
// "Moscow": [
// { name: "Alice", city: "Moscow" },
// { name: "Charlie", city: "Moscow" }
// ],
// "SPb": [
// { name: "Bob", city: "SPb" },
// { name: "Diana", city: "SPb" }
// ]
// }
// С функцией как селектором
const byAge = groupBy(people, (person) => {
if (person.age < 20) return "young";
if (person.age < 40) return "adult";
return "senior";
});
// Группировка по типу
const items = [
{ id: 1, type: "fruit", name: "apple" },
{ id: 2, type: "vegetable", name: "carrot" },
{ id: 3, type: "fruit", name: "banana" }
];
const byType = groupBy(items, "type");
// {
// "fruit": [{id: 1, ...}, {id: 3, ...}],
// "vegetable": [{id: 2, ...}]
// }
// Сложная функция группировки
const orders = [
{ id: 1, status: "completed", amount: 100 },
{ id: 2, status: "pending", amount: 200 },
{ id: 3, status: "completed", amount: 150 }
];
const grouped = groupBy(orders, (order) => `${order.status}_${order.amount > 150 ? 'large' : 'small'}`);
Версия Map для уникальных типов
function groupBy(arr, keyOrFn) {
const map = new Map();
const getKey = typeof keyOrFn === 'function' ? keyOrFn : (obj) => obj[keyOrFn];
arr.forEach((item) => {
const groupKey = getKey(item);
if (!map.has(groupKey)) {
map.set(groupKey, []);
}
map.get(groupKey).push(item);
});
return Object.fromEntries(map);
}
Версия с использованием findIndex
function groupBy(arr, keyOrFn) {
const getKey = typeof keyOrFn === 'function' ? keyOrFn : (obj) => obj[keyOrFn];
return arr.reduce((result, item) => {
const key = getKey(item);
const group = result.find((g) => Object.keys(g)[0] === key);
if (group) {
group[key].push(item);
} else {
result.push({ [key]: [item] });
}
return result;
}, []);
}
Расширенная версия с опциями
function groupBy(arr, selector, options = {}) {
const {
mapValue = (items) => items,
keySeparator = "_",
multiKey = false
} = options;
const getKey = typeof selector === 'function' ? selector : (obj) => obj[selector];
const result = {};
arr.forEach((item) => {
const key = String(getKey(item));
if (!result[key]) {
result[key] = [];
}
result[key].push(item);
});
// Применяем mapValue к каждой группе
Object.keys(result).forEach((key) => {
result[key] = mapValue(result[key]);
});
return result;
}
// Использование с опциями
const grouped = groupBy(people, "city", {
mapValue: (items) => items.map((item) => item.name)
});
// { "Moscow": ["Alice", "Charlie"], "SPb": ["Bob", "Diana"] }
Пошаговый разбор примера
const arr = [{name: "A", city: "Moscow"}, {name: "B", city: "SPb"}, {name: "C", city: "Moscow"}];
// Итерация 1: item = {name: "A", city: "Moscow"}, groupKey = "Moscow"
// result = {"Moscow": [{name: "A", city: "Moscow"}]}
// Итерация 2: item = {name: "B", city: "SPb"}, groupKey = "SPb"
// result = {"Moscow": [...], "SPb": [{name: "B", city: "SPb"}]}
// Итерация 3: item = {name: "C", city: "Moscow"}, groupKey = "Moscow"
// result = {"Moscow": [{name: "A", ...}, {name: "C", ...}], "SPb": [...]}
Сравнение подходов
| Подход | Плюсы | Минусы |
|---|---|---|
| Object (string ключи) | Просто, быстро | Только строковые ключи |
| Map | Любые ключи, сохраняет порядок | Сложнее преобразовать |
| Reduce с объектом | Стандартный pattern | Нужна проверка существования |
| Reduce с findIndex | Сохраняет порядок вставки | Медленнее O(n²) |
Реальные применения
- Фильтрация по категориям: группировка товаров по типу
- Отчёты: группировка данных по месяцам, регионам
- UI компоненты: группировка опций в select
- Аналитика: агрегирование событий по типу
Ключевые моменты
- reduce(): однопроходный алгоритм O(n)
- Функция или ключ: гибкость в выборе критерия группировки
- Проверка существования: инициализируем массив если ключа нет
- String() преобразование: для сложных типов ключей
- Расширяемость: легко добавить mapValue для трансформации групп