Перевод статьи «Array Grouping in JavaScript (2024)».
Группировка массивов — это задача, которую вы, скорее всего, реализовывали в JavaScript. Она напоминает выполнение GROUP BY в SQL. Имея набор данных, мы можем составить набор более высокого уровня, поместив похожие данные в группы и присвоив группам идентификаторы.
В этой статье я рассмотрю новые функции группировки массивов, вышедшие в 2024 году, а именно Object.groupBy и Map.groupBy.
Что касается TypeScript, поддержка этих API доступна начиная с TypeScript 5.4. Однако вам придется настроить tsconfig.json на ESNext. Когда они будут доступны в ES2024, вы сможете перейти на ES2024 или выше.
Группировка массивов до 2024 года
Группировка массивов в JavaScript — не новая концепция, мы уже реализовывали ее в различных вариантах. Например, можно применить циклы for или foreach, Array.prototype.reduce или функции groupBy в underscore.js или lodash.
Вот как мы группируем данные, используя функцию reduce(), если у нас есть список сотрудников:
interface Employee {
name: string;
department: string;
age: number;
manager?: Employee;
joined: Date
}
const ceo = {
name: «John Doe»,
department: «engineering»,
age: 47,
joined: new Date(«10-04-2020»)
}
const cfo = {
name: «Anna Maria»,
department: «finance»,
age: 45,
joined: new Date(«10-05-2020»)
}
const employees: Employee[] = [
ceo,
{
name: «Pop Jones Jr.»,
department: «finance»,
age: 30,
manager: cfo,
joined: new Date(«10-04-2021»)
},
{
name: «Sarah Clara»,
department: «engineering»,
age: 32,
manager: ceo,
joined: new Date(«10-05-2021»)
},
cfo,
{
name: «Funmi Kola»,
department: «engineering»,
age: 20,
manager: ceo,
joined: new Date(«10-05-2022»)
},
{
name: «Julius Maria»,
department: «sales»,
age: 27,
manager: cfo,
joined: new Date(«10-05-2022»)
}
]
const groupByDepartment = employees.reduce<Record<string, Employee[]>>((acc, employee) => {
const department = employee.department;
if (acc[department] === undefined) {
acc[department] = [];
}
acc[department].push(employee);
return acc;
}, {});
console.log(groupByDepartment);
Вывод для groupByDepartment должен быть таким:
{
«engineering»: [
{
«name»: «John Doe»,
«department»: «engineering»,
«age»: 47,
«joined»: «2020-10-03T22:00:00.000Z»
},
{
«name»: «Sarah Clara»,
«department»: «engineering»,
«age»: 32,
«manager»: {
«name»: «John Doe»,
«department»: «engineering»,
«age»: 47,
«joined»: «2020-10-03T22:00:00.000Z»
},
«joined»: «2021-10-04T22:00:00.000Z»
},
{
«name»: «Funmi Kola»,
«department»: «engineering»,
«age»: 20,
«manager»: {
«name»: «John Doe»,
«department»: «engineering»,
«age»: 47,
«joined»: «2020-10-03T22:00:00.000Z»
},
«joined»: «2022-10-04T22:00:00.000Z»
}
],
«finance»: [
{
«name»: «Pop Jones Jr.»,
«department»: «finance»,
«age»: 30,
«manager»: {
«name»: «Anna Maria»,
«department»: «finance»,
«age»: 45,
«joined»: «2020-10-04T22:00:00.000Z»
},
«joined»: «2021-10-03T22:00:00.000Z»
},
{
«name»: «Anna Maria»,
«department»: «finance»,
«age»: 45,
«joined»: «2020-10-04T22:00:00.000Z»
}
],
«sales»: [
{
«name»: «Julius Maria»,
«department»: «sales»,
«age»: 27,
«manager»: {
«name»: «Anna Maria»,
«department»: «finance»,
«age»: 45,
«joined»: «2020-10-04T22:00:00.000Z»
},
«joined»: «2022-10-04T22:00:00.000Z»
}
]
}
Группировка с помощью Object.groupBy
Функция Object.groupBy используется для группировки элементов итерируемого объекта по значению, которое возвращается предоставленной колбэк-функцией. Это значение должно быть чем-то, что может быть преобразовано в строку или символ.
Object.groupBy возвращает объект, в котором каждое свойство представляет собой группу, содержащую массив элементов. Использование такого объекта позволяет эргономично проводить деструктуризацию и предотвращает случайные коллизии с глобальными свойствами Object.
Используя тот же набор данных, с помощью Object.groupBy мы можем сгруппировать сотрудников по их отделам:
const groupByDepartment = Object.groupBy(employees, ({department}) => department)
Это дает тот же результат, что и метод reduce, но с меньшим количеством кода. Вывод для groupByDepartment должен быть следующим:
{
«engineering»: [
{
«name»: «John Doe»,
«department»: «engineering»,
«age»: 47,
«joined»: «2020-10-03T22:00:00.000Z»
},
{
«name»: «Sarah Clara»,
«department»: «engineering»,
«age»: 32,
«manager»: {
«name»: «John Doe»,
«department»: «engineering»,
«age»: 47,
«joined»: «2020-10-03T22:00:00.000Z»
},
«joined»: «2021-10-04T22:00:00.000Z»
},
{
«name»: «Funmi Kola»,
«department»: «engineering»,
«age»: 20,
«manager»: {
«name»: «John Doe»,
«department»: «engineering»,
«age»: 47,
«joined»: «2020-10-03T22:00:00.000Z»
},
«joined»: «2022-10-04T22:00:00.000Z»
}
],
«finance»: [
{
«name»: «Pop Jones Jr.»,
«department»: «finance»,
«age»: 30,
«manager»: {
«name»: «Anna Maria»,
«department»: «finance»,
«age»: 45,
«joined»: «2020-10-04T22:00:00.000Z»
},
«joined»: «2021-10-03T22:00:00.000Z»
},
{
«name»: «Anna Maria»,
«department»: «finance»,
«age»: 45,
«joined»: «2020-10-04T22:00:00.000Z»
}
],
«sales»: [
{
«name»: «Julius Maria»,
«department»: «sales»,
«age»: 27,
«manager»: {
«name»: «Anna Maria»,
«department»: «finance»,
«age»: 45,
«joined»: «2020-10-04T22:00:00.000Z»
},
«joined»: «2022-10-04T22:00:00.000Z»
}
]
}
Группировка с помощью Map.groupBy
Функция Map.groupBy аналогична Object.groupBy, за исключением того, что она возвращает Map, а заданный итерируемый массив может быть сгруппирован по любому произвольному значению. В данном случае набор данных можно сгруппировать с помощью объекта.
Возвращаясь к нашему набору данных, мы определили свойство manager для некоторых сотрудников и присвоили ему объект ceo или cfo. Мы можем сгруппировать сотрудников по их руководителю (manager), что будет выглядеть следующим образом:
const managerWithTeammates = Map.groupBy(employees, ({manager}) => manager)
Вывод для managerWithTeammates должен выглядеть так:
Map (3)
{undefined => [{
«name»: «John Doe»,
«department»: «engineering»,
«age»: 47,
«joined»: «2020-10-03T22:00:00.000Z»
}, {
«name»: «Anna Maria»,
«department»: «finance»,
«age»: 45,
«joined»: «2020-10-04T22:00:00.000Z»
}],
{
«name»: «Anna Maria»,
«department»: «finance»,
«age»: 45,
«joined»: «2020-10-04T22:00:00.000Z»
} => [{
«name»: «Pop Jones Jr.»,
«department»: «finance»,
«age»: 30,
«manager»: {
«name»: «Anna Maria»,
«department»: «finance»,
«age»: 45,
«joined»: «2020-10-04T22:00:00.000Z»
},
«joined»: «2021-10-03T22:00:00.000Z»
}, {
«name»: «Julius Maria»,
«department»: «sales»,
«age»: 27,
«manager»: {
«name»: «Anna Maria»,
«department»: «finance»,
«age»: 45,
«joined»: «2020-10-04T22:00:00.000Z»
},
«joined»: «2022-10-04T22:00:00.000Z»
}],
{
«name»: «John Doe»,
«department»: «engineering»,
«age»: 47,
«joined»: «2020-10-03T22:00:00.000Z»
} => [{
«name»: «Sarah Clara»,
«department»: «engineering»,
«age»: 32,
«manager»: {
«name»: «John Doe»,
«department»: «engineering»,
«age»: 47,
«joined»: «2020-10-03T22:00:00.000Z»
},
«joined»: «2021-10-04T22:00:00.000Z»
}, {
«name»: «Funmi Kola»,
«department»: «engineering»,
«age»: 20,
«manager»: {
«name»: «John Doe»,
«department»: «engineering»,
«age»: 47,
«joined»: «2020-10-03T22:00:00.000Z»
},
«joined»: «2022-10-04T22:00:00.000Z»
}]}
В этом примере у нас есть 3 группы:
CEO и CFO (генеральный и финансовый директор), у которых нет руководителя, с ключом объекта Map — undefined.
CFO, Anna Maria, у которой в подчинении два сотрудника. В качестве ключа объекта Map используется объект cfo.
CEO, John Doe, в подчинении которого находятся два сотрудника. В качестве ключа объекта Map используется объект ceo.
Заключение
Разве не удивительны новые API, которые появляются в JavaScript? Функции Object.groupBy и Map.groupBy упрощают группировку данных в массиве или итерируемом файле, и они более эргономичны, чем традиционный метод reduce. Они также уменьшают размер пакета, поскольку не требуют использования внешних библиотек, таких как lodash или underscore.js.
Напомним, что функция Map.groupBy используется в основном для группировки элементов, связанных с любым произвольным объектом, особенно если этот объект может меняться со временем. Если объект неизменен, можно представить его в виде строки и сгруппировать элементы с помощью Object.groupBy(). Если вы используете TypeScript, установите целевой параметр ESNext (или ES2024, когда он будет доступен).
Запись Группировка массивов в JavaScript (2024) впервые появилась techrocks.ru.