← Назад к вопросам

Как оставить в массиве уникальные значения?

1.6 Junior🔥 151 комментариев
#JavaScript Core

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI2 апр. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Получение уникальных значений из массива

Удаление дубликатов из массива — одна из самых частых задач в JavaScript. Существует несколько способов, каждый с разными особенностями.

Способ 1: Set (самый простой и современный)

Set — встроенная структура данных, которая хранит только уникальные значения:

const arr = [1, 2, 2, 3, 3, 3, 4];
const unique = [...new Set(arr)];
console.log(unique); // [1, 2, 3, 4]

Это самый быстрый способ для примитивных типов данных:

const mixed = ['a', 'b', 'a', 1, 1, 2, null, null, undefined, undefined];
const unique = [...new Set(mixed)];
console.log(unique); // ['a', 'b', 1, 2, null, undefined]

Способ 2: filter с indexOf

Для старых браузеров (ES5) можно использовать filter:

const arr = [1, 2, 2, 3, 3, 3, 4];
const unique = arr.filter((value, index, self) => 
  self.indexOf(value) === index
);
console.log(unique); // [1, 2, 3, 4]

Минус: медленный для больших массивов (O(n²)), потому что indexOf выполняется для каждого элемента.

Способ 3: for loop с объектом (быстрый для простых данных)

const arr = [1, 2, 2, 3, 3, 3, 4];
const seen = {};
const unique = [];

for (const value of arr) {
  if (!(value in seen)) {
    seen[value] = true;
    unique.push(value);
  }
}

console.log(unique); // [1, 2, 3, 4]

Минус: не работает с объектами, потому что объекты преобразуются в строки.

Способ 4: reduce

const arr = [1, 2, 2, 3, 3, 3, 4];
const unique = arr.reduce((acc, value) => 
  acc.includes(value) ? acc : [...acc, value], 
  []
);
console.log(unique); // [1, 2, 3, 4]

Минус: медленный (includes проверяет весь аккумулятор).

Способ 5: Для объектов и сложных типов

Для объектов нужен специальный подход:

const users = [
  { id: 1, name: 'Alice' },
  { id: 2, name: 'Bob' },
  { id: 1, name: 'Alice' }, // Дубликат
];

// По id (используя Map)
const uniqueById = Array.from(
  new Map(users.map(user => [user.id, user])).values()
);
console.log(uniqueById);
// [{ id: 1, name: 'Alice' }, { id: 2, name: 'Bob' }]

// По всему объекту (используя JSON.stringify)
const uniqueByObject = arr.filter((obj, index, self) =>
  index === self.findIndex(item => JSON.stringify(item) === JSON.stringify(obj))
);

Практические примеры в React

1. Удаление дубликатов в списке тегов

interface Post {
  id: string;
  tags: string[];
}

export function PostTags({ post }: { post: Post }) {
  const uniqueTags = [...new Set(post.tags)];
  
  return (
    <div>
      {uniqueTags.map(tag => (
        <span key={tag} className="tag">{tag}</span>
      ))}
    </div>
  );
}

2. Получение уникальных категорий

interface Product {
  id: string;
  category: string;
  name: string;
}

export function CategoryFilter({ products }: { products: Product[] }) {
  const categories = [...new Set(products.map(p => p.category))];
  
  return (
    <select>
      <option value="">All categories</option>
      {categories.map(cat => (
        <option key={cat} value={cat}>{cat}</option>
      ))}
    </select>
  );
}

3. Удаление дубликатов ID

const userIds = [1, 2, 2, 3, 3, 3];
const uniqueIds = [...new Set(userIds)];
const users = await fetchUsers(uniqueIds);

Сравнение производительности

// Для массива с 10000 элементами:

// Set: ~0.1ms
const arr = Array.from({length: 10000}, (_, i) => i % 100);
console.time('Set');
const unique1 = [...new Set(arr)];
console.timeEnd('Set'); // ~0.1ms

// filter + indexOf: ~50ms ❌ Медленно!
console.time('filter');
const unique2 = arr.filter((v, i) => arr.indexOf(v) === i);
console.timeEnd('filter'); // ~50ms

// for loop + объект: ~1ms
console.time('for loop');
const seen = {};
const unique3 = [];
for (const v of arr) {
  if (!(v in seen)) {
    seen[v] = true;
    unique3.push(v);
  }
}
console.timeEnd('for loop'); // ~1ms

Вывод: Set это всегда лучший выбор для современного кода.

Специальные случаи

1. Удаление null и undefined

const arr = [1, 2, null, 3, undefined, 2];
const unique = [...new Set(arr)].filter(Boolean);
// [1, 2, 3] (null и undefined удалены)

2. Case-insensitive уникальность для строк

const arr = ['Apple', 'apple', 'APPLE', 'Banana'];
const unique = [
  ...new Map(
    arr.map(item => [item.toLowerCase(), item])
  ).values()
];
// ['Apple', 'Banana'] (регистр игнорируется)

3. Уникальность по нескольким полям

const logs = [
  { userId: 1, action: 'login' },
  { userId: 1, action: 'login' }, // Дубликат
  { userId: 2, action: 'logout' },
];

const unique = [
  ...new Map(
    logs.map(log => [
      `${log.userId}:${log.action}`, 
      log
    ])
  ).values()
];

Когда использовать что

СпособИспользоватьПлюсыМинусы
SetВсегда для примитивовБыстро, читаемо, современно-
filter + indexOfСтарые браузерыРаботает вездеМедленно
for loopБольшие массивыБыстроМногословно
СпециальныеОбъекты, сложная логикаГибкоСложно

Итог

Для удаления дубликатов используй [...new Set(arr)] — это:

  • Самый быстрый способ
  • Самый читаемый код
  • Поддерживается всеми современными браузерами

Для сложных случаев с объектами используй Map или filter с кастомной логикой.

Как оставить в массиве уникальные значения? | PrepBro