Как оставить в массиве уникальные значения?
Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
Получение уникальных значений из массива
Удаление дубликатов из массива — одна из самых частых задач в 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 с кастомной логикой.