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

Зачем нужна коллекция Set?

2.0 Middle🔥 172 комментариев
#JavaScript Core

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

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

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

Зачем нужна коллекция Set

Set (множество) — это встроенная структура данных в JavaScript, которая хранит уникальные значения. Это мощный инструмент для работы с данными, когда нужно избежать дубликатов и быстро проверить наличие элемента.

Основные характеристики Set

  • Уникальность: каждое значение может быть в Set только один раз
  • Любые типы: может хранить числа, строки, объекты, функции
  • Порядок вставки: элементы сохраняют порядок добавления
  • Быстрая проверка: O(1) для проверки наличия элемента
  • Динамический размер: можно добавлять и удалять элементы

Создание и базовые операции

// Создание пустого Set
const emptySet = new Set();

// Создание Set с начальными значениями
const numbers = new Set([1, 2, 3, 3, 4, 4]);
console.log(numbers); // Set { 1, 2, 3, 4 }
console.log(numbers.size); // 4

// Добавление элемента
numbers.add(5);
console.log(numbers.size); // 5

// Проверка наличия
console.log(numbers.has(3)); // true
console.log(numbers.has(10)); // false

// Удаление элемента
numbers.delete(3);
console.log(numbers.has(3)); // false

// Очистка всех элементов
numbers.clear();
console.log(numbers.size); // 0

Практические примеры использования

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

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

// Или с использованием Array.from
const unique2 = Array.from(new Set(numbers));

// Удаление дубликатов из строк
const letters = "aabbccdd";
const uniqueLetters = [...new Set(letters)].join('');
console.log(uniqueLetters); // "abcd"

2. Отслеживание посещённых элементов

function findPath(graph, start, end) {
  const visited = new Set();
  const queue = [start];
  const parentMap = new Map();
  
  while (queue.length > 0) {
    const current = queue.shift();
    
    if (current === end) {
      // Восстанавливаем путь
      const path = [];
      let node = end;
      while (node) {
        path.unshift(node);
        node = parentMap.get(node);
      }
      return path;
    }
    
    if (!visited.has(current)) {
      visited.add(current);
      for (const neighbor of graph[current]) {
        if (!visited.has(neighbor)) {
          queue.push(neighbor);
          parentMap.set(neighbor, current);
        }
      }
    }
  }
  return null;
}

3. Быстрая проверка наличия элемента

// Неэффективно: O(n) для каждой проверки
const allowedRoles = ['admin', 'moderator', 'user'];
if (allowedRoles.includes(userRole)) { }

// Эффективно: O(1) для каждой проверки
const allowedRoles = new Set(['admin', 'moderator', 'user']);
if (allowedRoles.has(userRole)) { }

4. Пересечение и объединение массивов

const array1 = [1, 2, 3, 4];
const array2 = [3, 4, 5, 6];

// Объединение (union)
const union = new Set([...array1, ...array2]);
console.log([...union]); // [1, 2, 3, 4, 5, 6]

// Пересечение (intersection)
const set2 = new Set(array2);
const intersection = new Set(array1.filter(x => set2.has(x)));
console.log([...intersection]); // [3, 4]

// Разность (difference)
const difference = new Set(array1.filter(x => !set2.has(x)));
console.log([...difference]); // [1, 2]

5. Отслеживание активных подписчиков

class EventEmitter {
  constructor() {
    this.subscribers = new Set();
  }
  
  subscribe(callback) {
    this.subscribers.add(callback);
    // Возвращаем функцию для отписки
    return () => this.subscribers.delete(callback);
  }
  
  emit(data) {
    this.subscribers.forEach(callback => callback(data));
  }
}

const emitter = new EventEmitter();
const unsubscribe1 = emitter.subscribe(data => console.log('Listener 1:', data));
const unsubscribe2 = emitter.subscribe(data => console.log('Listener 2:', data));

emitter.emit('Hello'); // Вызовет обоих слушателей
unsubscribe1();
emitter.emit('World'); // Вызовет только второго

Set vs Array

ОперацияSetArray
ДобавлениеO(1)O(1) amortized
УдалениеO(1)O(n)
ПоискO(1)O(n)
Хранение дубликатовНетДа
СортировкаНет встроеннойДа, sort()
Индексный доступНетДа
ИтерацияДа, в порядке вставкиДа, по индексам

Методы и свойства Set

const set = new Set([1, 2, 3]);

// Проверка размера
console.log(set.size); // 3

// Итерация
for (const value of set) {
  console.log(value);
}

// Методы
set.forEach((value, key, setObj) => {
  console.log(value);
});

// Получение значений
console.log([...set]); // [1, 2, 3]

// Методы итератора
const iterator = set.values();
console.log(iterator.next()); // { value: 1, done: false }

Set с объектами

const users = new Set();
const user1 = { id: 1, name: 'Alice' };
const user2 = { id: 2, name: 'Bob' };

users.add(user1);
users.add(user2);
users.add(user1); // Не добавится, так как user1 уже в Set

console.log(users.size); // 2
console.log(users.has(user1)); // true

// Важно: Set сравнивает по ссылке, не по значению
const user1Copy = { id: 1, name: 'Alice' };
console.log(users.has(user1Copy)); // false, это другой объект

WeakSet для объектов

Для специальных случаев существует WeakSet, который хранит только ссылки на объекты и не препятствует garbage collection:

const weakSet = new WeakSet();
const obj1 = { id: 1 };
const obj2 = { id: 2 };

weakSet.add(obj1);
weakSet.add(obj2);

console.log(weakSet.has(obj1)); // true

// WeakSet полезен для отслеживания объектов без утечек памяти

Вывод

Set — это незаменимая структура данных для многих задач. Её главное преимущество — гарантированная уникальность значений и быстрая проверка наличия элемента O(1). Используйте Set вместо Array когда:

  • Нужно избежать дубликатов
  • Часто проверяете наличие элемента
  • Удаляете элементы часто
  • Не нужен индексный доступ