Как объединить два массива в JavaScript и удалить дубликаты?
Объединение массивов с удалением дубликатов: лучшие практики
Вы абсолютно правы — concat просто склеивает массивы, не заботясь об уникальности элементов. Для решения вашей задачи есть несколько элегантных способов. Рассмотрим их от простого к более сложному.
1. Использование Set (самый простой и быстрый способ для примитивов)
Объект Set в JavaScript автоматически хранит только уникальные значения. Это идеальное решение для чисел и строк:
const arr1 = [1, 2, 3, 4, 5];
const arr2 = [3, 4, 5, 6, 7];
const merged = [...new Set([...arr1, ...arr2])];
console.log(merged); // [1, 2, 3, 4, 5, 6, 7]
Как это работает:
[...arr1, ...arr2]— spread-оператор распаковывает оба массива в один новый массив (как concat, но быстрее и современнее).new Set()— создаёт коллекцию уникальных значений из полученного массива.[...set]— обратная распаковка Set обратно в массив.
Этот метод работает за O(n) и отлично подходит для 99% случаев с примитивами.
2. Метод filter() — более гибкий подход
Если вам нужно больше контроля (например, сохранить порядок или применить сложную логику сравнения):
const arr1 = [1, 2, 3, 4, 5];
const arr2 = [3, 4, 5, 6, 7];
const merged = arr1.concat(
arr2.filter(item => !arr1.includes(item))
);
console.log(merged); // [1, 2, 3, 4, 5, 6, 7]
Логика: мы берём arr1 целиком, а из arr2 добавляем только те элементы, которых нет в arr1. Минус — метод includes делает O(n²) на больших массивах (10000+ элементов).
3. Сложный случай: объединение массивов объектов
Для объектов метод Set не сработает, так как объекты сравниваются по ссылке. Два одинаковых по содержимому объекта будут считаться разными:
const users1 = [{ id: 1, name: 'Alice' }, { id: 2, name: 'Bob' }];
const users2 = [{ id: 2, name: 'Bob' }, { id: 3, name: 'Charlie' }];
// Set не поможет — объекты разные по ссылке
const wrongMerge = [...new Set([...users1, ...users2])]; // 4 элемента, есть дубль
// Правильное решение — фильтрация по уникальному ключу (например, id):
const mergedUsers = [
...users1,
...users2.filter(
user2 => !users1.some(user1 => user1.id === user2.id)
)
];
console.log(mergedUsers);
// [{ id: 1, name: 'Alice' }, { id: 2, name: 'Bob' }, { id: 3, name: 'Charlie' }]
Здесь some() проверяет, есть ли уже объект с таким id в первом массиве. Для больших массивов (1000+ объектов) используйте Map для оптимизации до O(n):
function mergeUniqueByKey(arr1, arr2, key) {
const map = new Map();
[...arr1, ...arr2].forEach(item => {
map.set(item[key], item);
});
return Array.from(map.values());
}
const result = mergeUniqueByKey(users1, users2, 'id');
console.log(result);
// [{ id: 1, name: 'Alice' }, { id: 2, name: 'Bob' }, { id: 3, name: 'Charlie' }]
Рекомендации по производительности
- Для массивов до 1000 элементов — любой метод подойдёт.
- Для 1000-100000 элементов — используйте Set или Map (O(n)).
- Для массивов с объектами — всегда используйте Map с уникальным ключом.
- Современный код (ES6+) — отдавайте предпочтение Set/spread, это кратко и читаемо.
Выберите подход под вашу задачу. Для простых чисел и строк — Set будет идеальным решением!
<<Альтернативный подход: reduce + includes для наглядности
Если вам не нравится синтаксис Set или вы хотите явно показать логику объединения, можно использовать reduce. Этот метод отлично подходит для обучения, так как шаг за шагом демонстрирует процесс:
const arr1 = [1, 2, 3, 4, 5];
const arr2 = [3, 4, 5, 6, 7];
const merged = arr2.reduce((acc, item) => {
if (!acc.includes(item)) {
acc.push(item);
}
return acc;
}, [...arr1]); // начинаем с копии arr1
console.log(merged); // [1, 2, 3, 4, 5, 6, 7]
Как это работает: мы берём arr1 как начальное значение аккумулятора, затем проходим по arr2 и добавляем только те элементы, которых ещё нет в аккумуляторе.
Дополнение: объединение нескольких массивов
Если у вас не два, а три и более массивов, удобно использовать цепочку методов или flat + Set:
const arrays = [[1,2,3], [3,4,5], [5,6,7]];
const merged = [...new Set(arrays.flat())];
console.log(merged); // [1, 2, 3, 4, 5, 6, 7]
Метод flat() (глубина по умолчанию 1) объединяет все подмассивы в один, а Set удаляет дубли. Это лаконичное решение для произвольного количества массивов.
Важно: все описанные методы (кроме Map для объектов) работают только с примитивами. Для сложных объектов всегда используйте сравнение по уникальному идентификатору.