Как работает функция groupBy в JavaScript
Что проверяют
Знаете ли вы, что группировка теперь есть в самом языке, и умеете ли написать её сами. Следом обычно просят реализовать groupBy без встроенного метода и оценить сложность.
Как отвечать
Начните со стандарта. В ES2024 появились два статических метода:
Object.groupBy(items, callback): принимает любой итерируемый объект и функцию(item, index) => key, возвращает объект, где каждому ключу соответствует массив элементов. Объект создаётся без прототипа, поэтомуhasOwnPropertyна нём не вызвать, нуженObject.hasOwn;Map.groupBy(items, callback): то же самое, но вMap. Ключи не приводятся к строке, группировать можно по объекту или числу без потери типа;- поддержка: все актуальные браузеры и Node.js начиная с 21-й версии. TypeScript узнает метод только при свежей
libвtsconfig, для старых браузеров нужен полифил изcore-js.
Метод статический, а не array.groupBy(): вариант на прототипе массива ломал старые сайты, которые сами дописывали туда одноимённый метод.
Своя реализация занимает несколько строк: reduce или for...of, аккумулятор Object.create(null) или new Map(), ключ вычисляется функцией, элемент добавляется через push. Сложность O(n) по времени и по памяти. Хорошо добавить, что функция лучше строкового ключа: можно группировать по вычисляемому признаку, например по первой букве или диапазону цены. _.groupBy из lodash принимает и то и другое.
Где спотыкаются
Пишут аккумулятор через спред: { ...acc, [key]: [...(acc[key] ?? []), item] }. Каждый шаг копирует весь объект и массив, и линейный алгоритм становится квадратичным.
Берут {} как аккумулятор и не думают о ключах вроде constructor или __proto__: они совпадут со свойствами прототипа и дадут странный результат.
Ждут от Object.groupBy сохранения типа ключа. Число 1 и строка "1" попадут в одну группу, а объекты в роли ключа превратятся в "[object Object]". Для таких случаев есть Map.groupBy.