Как избавиться от дубликатов в массиве: JavaScript решения
Различные способы удаления дубликатов из массива
Как удалить дубликаты из массива наиболее простым и быстрым способом?
Использование объекта Set является самым лаконичным и эффективным методом. Set автоматически хранит только уникальные значения. Преобразование массива в Set и обратно в массив удаляет все повторы.
const arr = [1, 2, 2, 3, 4, 4, 5];
const unique = [...new Set(arr)];
console.log(unique); // [1, 2, 3, 4, 5]
Js как сделать (как сделать на javascript)
Возможные проблемы: Set работает только с примитивными типами (числа, строки, булевы) и сверяет по строгому равенству. Для объектов он не отличит разные ссылки с одинаковым содержимым. Также сохраняется порядок первых вхождений.
Как удалить дубликаты с помощью метода filter и indexOf?
Метод filter в комбинации с indexOf позволяет оставить только первое вхождение каждого элемента. Для каждого элемента проверяется, совпадает ли его индекс с первым индексом этого значения в массиве.
const arr = [1, 2, 2, 3, 4, 4, 5];
const unique = arr.filter((item, index) => arr.indexOf(item) === index);
console.log(unique); // [1, 2, 3, 4, 5]
Проблема: Данный метод имеет сложность O(n^2), так как indexOf выполняет линейный поиск для каждого элемента. Для больших массивов производительность сильно падает. Кроме того, для NaN индекс не находится, поэтому NaN не будет учтен.
Как удалить дубликаты с помощью reduce?
Метод reduce позволяет накопить уникальные элементы, проверяя наличие каждого нового элемента в аккумуляторе.
const arr = [1, 2, 2, 3, 4, 4, 5];
const unique = arr.reduce((acc, item) => {
if (!acc.includes(item)) acc.push(item);
return acc;
}, []);
console.log(unique); // [1, 2, 3, 4, 5]
Проблема: includes также выполняет линейный поиск, что даёт O(n^2). Код менее читаем, чем Set. Для объектов сравниваются ссылки, а не содержимое.
Как удалить дубликаты с помощью forEach и includes?
Использование цикла forEach с проверкой через includes, ещё один вариант, аналогичный reduce.
const arr = [1, 2, 2, 3, 4, 4, 5];
const unique = [];
arr.forEach(item => {
if (!unique.includes(item)) unique.push(item);
});
console.log(unique); // [1, 2, 3, 4, 5]
Проблема: Те же недостатки, что и у filter+indexOf: квадратичная сложность и неучёт NaN.
Как удалить дубликаты из массива объектов по ключу?
Для объектов нельзя полагаться на Set, если объекты разные по ссылке, но одинаковые по содержимому. Используется хеш-объект (или Map) для отслеживания уникальных значений по свойству.
const users = [
{ id: 1, name: 'Alice' },
{ id: 2, name: 'Bob' },
{ id: 1, name: 'Alice' }
];
const unique = users.filter((user, index, self) =>
index === self.findIndex(u => u.id === user.id)
);
console.log(unique); // [{id:1, name:'Alice'}, {id:2, name:'Bob'}]
Проблема: findIndex также имеет сложность O(n^2). Для больших массивов лучше использовать Map или Reduce с хешем.
Пример 1: Удаление дубликатов из массива чисел с сохранением первого вхождения (Set)
const numbers = [3, 1, 2, 3, 3, 4, 1, 5];
const result = [...new Set(numbers)];
console.log(result);
[3, 1, 2, 4, 5]
Пример 2: Удаление дубликатов из массива строк без учета регистра
const words = ['apple', 'Apple', 'banana', 'BANANA', 'apple'];
const lowerSet = new Set();
const result = words.filter(word => {
const lower = word.toLowerCase();
if (!lowerSet.has(lower)) {
lowerSet.add(lower);
return true;
}
return false;
});
console.log(result);
['apple', 'banana']
Пример 3: Удаление дубликатов из массива объектов по свойству id с использованием Map
const items = [
{ id: 10, name: 'Item1' },
{ id: 20, name: 'Item2' },
{ id: 10, name: 'Item1 duplicate' }
];
const map = new Map();
items.forEach(item => {
if (!map.has(item.id)) {
map.set(item.id, item);
}
});
const result = Array.from(map.values());
console.log(result);
[{ id: 10, name: 'Item1' }, { id: 20, name: 'Item2' }]
Пример 4: Удаление дубликатов с использованием reduce и хеша для объектов
const products = [
{ code: 'A1', price: 100 },
{ code: 'B2', price: 200 },
{ code: 'A1', price: 150 }
];
const result = products.reduce((acc, item) => {
if (!acc.some(p => p.code === item.code)) {
acc.push(item);
}
return acc;
}, []);
console.log(result);
[{ code: 'A1', price: 100 }, { code: 'B2', price: 200 }]
Пример 5: Сравнение производительности Set и filter+indexOf для большого массива
const bigArray = Array.from({ length: 10000 }, () => Math.floor(Math.random() * 1000));
console.time('Set');
const uniqueSet = [...new Set(bigArray)];
console.timeEnd('Set');
console.time('FilterIndexOf');
const uniqueFilter = bigArray.filter((item, index) => bigArray.indexOf(item) === index);
console.timeEnd('FilterIndexOf');
Set: 0.123ms FilterIndexOf: 12.456ms