Разминочные задачи («уникальные элементы», «сгруппировать», «развернуть строку», «разбить на чанки») решаются в 2-5 строк, если знать идиомы. На собесе они проверяют беглость: решили за минуту, проговорили сложность, учли крайний случай.
Набор инструментов
Методы массивов. map, filter, reduce, some, every, find, findIndex, flat, flatMap, includes, slice, at.
Map и Set. Всё, что требует «встречалось ли», «сколько раз», «по ключу», решается за O(n) через Set и Map вместо вложенных циклов.
Array.from. Создать массив нужной длины и заполнить: Array.from({ length: n }, (_, i) => i).
Типовые приёмы
// уникальные значения, порядок сохраняется
const unique = (arr) => [...new Set(arr)];
// уникальные по ключу
const uniqueBy = (arr, key) => [...new Map(arr.map((x) => [x[key], x])).values()];
// внимание: при дублях останется последний элемент, а позиция будет у первого
// подсчёт частот
const countBy = (arr) => arr.reduce((acc, x) => {
acc[x] = (acc[x] ?? 0) + 1;
return acc;
}, {});
// группировка
const byRole = Object.groupBy(users, (u) => u.role);
// чанки по n
const chunk = (arr, n) =>
Array.from({ length: Math.ceil(arr.length / n) }, (_, i) => arr.slice(i * n, i * n + n));
// диапазон
const range = (from, to) => Array.from({ length: to - from }, (_, i) => from + i);
// пересечение за O(n + m)
const intersect = (a, b) => { const s = new Set(b); return a.filter((x) => s.has(x)); };
Сортировка
- Числа:
arr.toSorted((a, b) => a - b); без компаратора сравнение будет строковым. - Строки на русском:
a.localeCompare(b, 'ru')илиnew Intl.Collator('ru').compareдля больших массивов. - По нескольким полям:
(a, b) => a.age - b.age || a.name.localeCompare(b.name). - Сортировка стабильна, равные элементы сохраняют порядок.
Строки
const reverse = (s) => [...s].reverse().join(''); // по символам Unicode, не ломает эмодзи
const capitalize = (s) => s.charAt(0).toUpperCase() + s.slice(1);
const isPalindrome = (s) => {
const clean = s.toLowerCase().replace(/[^a-zа-яё0-9]/g, '');
return clean === [...clean].reverse().join('');
};
const words = (s) => s.trim().split(/\s+/).filter(Boolean);
split('') режет по UTF-16 единицам и ломает эмодзи, spread [...s] нет.
Числа и форматирование
const clamp = (x, min, max) => Math.min(Math.max(x, min), max);
const sum = (arr) => arr.reduce((a, b) => a + b, 0); // начальное значение обязательно для пустого массива
new Intl.NumberFormat('ru-RU', { style: 'currency', currency: 'RUB' }).format(1234.5); // '1 234,50 ₽'
Деньги считайте в копейках целыми числами, чтобы не ловить 0.1 + 0.2.
Сложность
Проговаривайте сложность сразу:
includes/indexOfвнутриfilterдаёт O(n·m),Setдаёт O(n + m);sortэто O(n log n);reduceс[...acc, x]на каждом шаге это O(n²): копирование растущего массива. Используйтеpushв аккумулятор.
Чистота
По умолчанию не мутируйте вход: sort, reverse, splice меняют исходный массив. Используйте toSorted, toReversed, slice, spread. Если задача явно про «на месте» (in-place), скажите это вслух.
Крайние случаи
Пустой массив, один элемент, отрицательные числа, n больше длины, дубли, регистр и пробелы в строках, NaN. Хотя бы назовите их интервьюеру.
Что спросят на собесе
- Уберите дубли из массива, в том числе по ключу объекта.
- Сгруппируйте или посчитайте элементы, разбейте на чанки.
- Отсортируйте по нескольким полям, по-русски.
- Какая сложность у вашего решения и можно ли быстрее.
- Мутирует ли ваша функция входные данные.