Set (Множество)
Set — коллекция уникальных значений без дубликатов. Каждое значение может присутствовать только один раз. Проверка наличия элемента — O(1).
Зачем нужно
Set решает задачу уникальности за O(1): удаление дубликатов, проверка «видели ли мы это значение», операции над множествами (объединение, пересечение, разность). Без Set эти задачи требуют O(n) на каждую проверку.
Где используется
- Удаление дубликатов из массива
- Проверка уникальности (уникальные посетители, уникальные слова)
- Теги, категории, фильтры
- Математические операции над множествами
- Отслеживание посещённых узлов в BFS/DFS
Предпосылки
Set в JavaScript
// Создание
const set = new Set();
const fromArray = new Set([1, 2, 3, 2, 1]); // {1, 2, 3}
const fromString = new Set('hello'); // {'h', 'e', 'l', 'o'}
// Основные операции
set.add(1); // добавить O(1)
set.add(2);
set.add(1); // дубликат — игнорируется
set.has(1); // true O(1)
set.has(3); // false O(1)
set.delete(1); // true O(1)
set.size; // 1
set.clear(); // очистить
// Итерация (порядок вставки сохраняется)
const colors = new Set(['red', 'green', 'blue']);
for (const color of colors) {
console.log(color); // red, green, blue
}
colors.forEach(color => console.log(color));
const arr = [...colors]; // ['red', 'green', 'blue']
Удаление дубликатов
// Самый простой способ удалить дубликаты
const numbers = [1, 2, 3, 2, 4, 1, 5, 3];
const unique = [...new Set(numbers)]; // [1, 2, 3, 4, 5]
// Уникальные объекты (Set сравнивает по ссылке!)
const users = [
{ id: 1, name: 'Alice' },
{ id: 2, name: 'Bob' },
{ id: 1, name: 'Alice' }, // другой объект, та же data
];
// Set НЕ уберёт дубликаты объектов (разные ссылки)
const uniqueUsers = [...new Set(users)]; // всё ещё 3 элемента
// Решение: уникальность по ключу
function uniqueBy(array, key) {
const seen = new Set();
return array.filter(item => {
const value = item[key];
if (seen.has(value)) return false;
seen.add(value);
return true;
});
}
console.log(uniqueBy(users, 'id'));
// [{ id: 1, name: 'Alice' }, { id: 2, name: 'Bob' }]
Операции над множествами
const A = new Set([1, 2, 3, 4]);
const B = new Set([3, 4, 5, 6]);
// Объединение (Union): A ∪ B
const union = new Set([...A, ...B]);
// {1, 2, 3, 4, 5, 6}
// Пересечение (Intersection): A ∩ B
const intersection = new Set([...A].filter(x => B.has(x)));
// {3, 4}
// Разность (Difference): A \ B
const difference = new Set([...A].filter(x => !B.has(x)));
// {1, 2}
// Симметрическая разность: (A \ B) ∪ (B \ A)
const symmetricDiff = new Set(
[...A].filter(x => !B.has(x)).concat([...B].filter(x => !A.has(x)))
);
// {1, 2, 5, 6}
// Подмножество: A ⊆ B
function isSubset(setA, setB) {
return [...setA].every(x => setB.has(x));
}
// ES2025+ — встроенные методы
// A.union(B), A.intersection(B), A.difference(B),
// A.symmetricDifference(B), A.isSubsetOf(B), A.isSupersetOf(B)
WeakSet
WeakSet хранит только объекты и не препятствует сборке мусора.
const weakSet = new WeakSet();
let obj = { data: 'important' };
weakSet.add(obj);
console.log(weakSet.has(obj)); // true
obj = null; // объект может быть собран GC
// weakSet больше не содержит ссылку
// Не поддерживает: size, итерацию, clear
// Используется для: отслеживание объектов без утечек памяти
Практические примеры
// Подсчёт уникальных посетителей
const visitors = new Set();
function trackVisitor(userId) {
visitors.add(userId);
}
trackVisitor('user_1');
trackVisitor('user_2');
trackVisitor('user_1'); // дубликат
console.log(visitors.size); // 2
// Проверка наличия дубликатов в массиве — O(n)
function hasDuplicates(array) {
return new Set(array).size !== array.length;
}
// Первый неповторяющийся символ
function firstUnique(str) {
const count = {};
for (const ch of str) {
count[ch] = (count[ch] || 0) + 1;
}
for (const ch of str) {
if (count[ch] === 1) return ch;
}
return null;
}
Сложность операций
| Операция | Сложность |
|---|---|
add(value) |
O(1) |
has(value) |
O(1) |
delete(value) |
O(1) |
size |
O(1) |
| Итерация | O(n) |
Частые ошибки
- Думать, что Set дедуплицирует объекты по содержимому. Set сравнивает по ссылке (===)
- Забывать, что Set сохраняет порядок вставки. Это гарантировано спецификацией
- Использовать массив вместо Set для проверок
includes.arr.includes— O(n),set.has— O(1) - Не знать о WeakSet. Для отслеживания объектов без утечек памяти
Практика
- Реализуйте функции
union,intersection,differenceдля Set - Напишите
findCommonElements(arr1, arr2, arr3)— элементы, которые есть во всех трёх массивах - Реализуйте
longestConsecutiveSequence([100, 4, 200, 1, 3, 2])→ 4 (последовательность 1,2,3,4)
Связанные темы
- Map (ключ-значение, а не просто значение)
- Hash Table (Set реализован на хэш-таблице)
- Array (альтернатива)
- Graph (visited set для BFS/DFS)
Ресурсы
- MDN — Set
- learn.javascript.ru — Set и WeakSet
- TC39 — Set methods proposal (union, intersection и др.)