Как объединить (смержить/сплющить) массив массивов в JavaScript?
Решение: объединение массивов в JavaScript
Проблема, которую вы описали, называется flattening (сплющивание/выравнивание) массива. В современном JavaScript есть несколько способов это сделать. Давайте разберем их от простого к сложному.
1. Метод flat() (ES2019) — самый простой способ
Начиная с ECMAScript 2019, у массивов появился встроенный метод flat(). Он принимает один необязательный аргумент — глубину вложенности. По умолчанию глубина = 1.
// Простой случай (один уровень вложенности)
const nestedArrays = [[1, 2, 3], [4, 5, 6], [7, 8, 9]];
const flattened = nestedArrays.flat();
console.log(flattened); // [1, 2, 3, 4, 5, 6, 7, 8, 9]
// Глубокая вложенность — укажите глубину
const deepNested = [1, [2, [3, [4, 5]]], 6];
const deepFlattened = deepNested.flat(2); // сплющит на 2 уровня
console.log(deepFlattened); // [1, 2, 3, [4, 5], 6] — массив [4,5] остался
// Чтобы сплющить полностью, используйте Infinity
const fullyFlattened = deepNested.flat(Infinity);
console.log(fullyFlattened); // [1, 2, 3, 4, 5, 6]
2. Классический подход через reduce() и concat()
Если вам нужно поддерживать старые браузеры или вы хотите понять, как это работает "под капотом":
const nestedArrays = [[1, 2, 3], [4, 5, 6], [7, 8, 9]];
const flattened = nestedArrays.reduce((acc, current) => {
return acc.concat(current);
}, []);
console.log(flattened); // [1, 2, 3, 4, 5, 6, 7, 8, 9]
// Для глубокой вложенности — рекурсивная версия
function flattenDeep(arr) {
return arr.reduce((acc, val) => {
if (Array.isArray(val)) {
return acc.concat(flattenDeep(val));
} else {
return acc.concat(val);
}
}, []);
}
const deepNested = [1, [2, [3, [4, 5]]], 6];
console.log(flattenDeep(deepNested)); // [1, 2, 3, 4, 5, 6]
3. Использование spread-оператора (для одного уровня)
Этот способ работает только для одного уровня вложенности:
const nestedArrays = [[1, 2, 3], [4, 5, 6], [7, 8, 9]];
const flattened = [].concat(...nestedArrays);
console.log(flattened); // [1, 2, 3, 4, 5, 6, 7, 8, 9]
// Или с помощью spread в новом массиве
const flattened2 = [...nestedArrays[0], ...nestedArrays[1], ...nestedArrays[2]];
// Но это неудобно, если массивов много
4. Метод flatMap() (если нужно трансформировать)
flatMap() сначала применяет функцию к каждому элементу, а затем сплющивает результат на один уровень. Полезно, когда нужно не просто объединить, но и изменить данные:
const arrays = [[1, 2], [3, 4], [5, 6]];
const result = arrays.flatMap(arr => arr.map(x => x * 2));
console.log(result); // [2, 4, 6, 8, 10, 12]
Важные моменты:
- Производительность:
flat()работает быстрее всего, так как это нативный метод - Совместимость:
flat()поддерживается во всех современных браузерах и Node.js 11+. Для старых окружений используйтеreduce() - Пустые элементы:
flat()удаляет пустые слоты из массива ([1, , 3].flat()→[1, 3]) - Глубина: Всегда используйте
Infinity, если не знаете точную глубину вложенности
Рекомендую использовать flat(Infinity) для большинства задач — это самый элегантный и безопасный способ.
Альтернативный подход: ручная рекурсия и генераторы
Если вы хотите полностью контролировать процесс и не использовать встроенные методы (например, для учебных целей или специфических требований), можно написать свою рекурсивную функцию или использовать генераторы.
Рекурсивная функция с циклом
function flattenArray(arr) {
const result = [];
for (let i = 0; i < arr.length; i++) {
const element = arr[i];
if (Array.isArray(element)) {
// Если элемент — массив, рекурсивно сплющиваем его
const flatSubArray = flattenArray(element);
// Добавляем все элементы из сплющенного подмассива
for (let j = 0; j < flatSubArray.length; j++) {
result.push(flatSubArray[j]);
}
} else {
// Если не массив — просто добавляем
result.push(element);
}
}
return result;
}
const deepNested = [1, [2, [3, [4, 5]]], 6];
console.log(flattenArray(deepNested)); // [1, 2, 3, 4, 5, 6]
Использование генератора (для ленивых вычислений)
Генераторы особенно полезны, если массив огромный и вы не хотите создавать новый массив целиком в памяти:
function* flattenGenerator(arr) {
for (const item of arr) {
if (Array.isArray(item)) {
yield* flattenGenerator(item); // рекурсивно делегируем
} else {
yield item;
}
}
}
const deepNested = [1, [2, [3, [4, 5]]], 6];
const flatIterator = flattenGenerator(deepNested);
console.log([...flatIterator]); // [1, 2, 3, 4, 5, 6]
Плюсы этого подхода:
- Полный контроль над логикой
- Генераторы экономят память при работе с большими данными
- Можно легко модифицировать (например, добавлять отсев пустых значений)
Минусы:
- Кода больше, чем при использовании
flat() - Медленнее нативных методов
Для продакшена используйте flat(), а эти подходы — для глубокого понимания или нестандартных задач.
Ответов пока нет.
Войдите чтобы оставить ответ