Как избавиться от дубликатов в массиве: JavaScript решения

Раздел: 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

Как сделать на JavaScript - comments

En
Js как сделать (javascript)