Кратко
Секция статьи "Кратко"Set
(по-русски говорят множество) — коллекция для хранения уникальных значений любого типа. Одно и то же значение нельзя добавить в Set
больше одного раза.
Set
— это неиндексированная коллекция, положить элемент в коллекцию можно, но достать нельзя. По элементам коллекции можно итерироваться.
Основные методы для работы с коллекцией:
add
— добавить элемент.delete
— удалить элемент.has
— проверить, есть ли элемент в коллекции.clear
— очистить коллекцию.forEach
— выполнить функцию для каждого элемента в коллекции, аналогично одноимённому методу массива.
Содержит свойство size
для получения количества элементов в коллекции.
Пример
Секция статьи "Пример"const uniqueIds = new Set()uniqueIds.add(123)uniqueIds.add(456)uniqueIds.add(111)uniqueIds.add(123)console.log(uniqueIds.size)// 3console.log(uniqueIds.has(111))// trueuniqueIds.delete(111)console.log(uniqueIds.size)// 2uniqueIds.clear()console.log(uniqueIds.size)// 0
const uniqueIds = new Set() uniqueIds.add(123) uniqueIds.add(456) uniqueIds.add(111) uniqueIds.add(123) console.log(uniqueIds.size) // 3 console.log(uniqueIds.has(111)) // true uniqueIds.delete(111) console.log(uniqueIds.size) // 2 uniqueIds.clear() console.log(uniqueIds.size) // 0
Как понять
Секция статьи "Как понять"Коллекция Set
может хранить произвольный набор значений — нет разницы, хранить в коллекции примитивные типы, объекты или массивы. Set
гарантирует, что одно и то же значение не может попасть в коллекцию больше одного раза. Если нам нужно получить коллекцию уникальных значений из массива неуникальных — Set
один из способов этого достичь.
Добавляйте элемент в массив и множество, чтобы понять разницу:
Создание коллекции
Секция статьи "Создание коллекции"Коллекция создаётся при помощи конструктора.
Можно создать пустой Set
:
const set = new Set()console.log(set.size)// 0
const set = new Set() console.log(set.size) // 0
Или сразу добавить в него элементы. Для этого нужно передать в конструктор итерируемый список значений. Обычно это массив:
const filled = new Set([1, 2, 3, 3, 3, 'hello'])console.log(filled.size)// 4
const filled = new Set([1, 2, 3, 3, 3, 'hello']) console.log(filled.size) // 4
Работа с коллекцией
Секция статьи "Работа с коллекцией"Set
предоставляет небольшой набор методов, но их достаточно в большинстве случаев.
Добавляют элемент в Set
с помощью метода add
, а удаляют с помощью delete
. В оба метода передаётся элемент, который нужно добавить или удалить:
const filled = new Set([1, 2, 3, '3', 3, 'hello'])filled.add(100)filled.delete(1)
const filled = new Set([1, 2, 3, '3', 3, 'hello']) filled.add(100) filled.delete(1)
Количество элементов в множестве хранится в свойстве size
. Проверить количество элементов в множестве filled
:
console.log(filled.size)// 5
console.log(filled.size) // 5
Set
позволяет проверить, был ли элемент уже добавлен. За это отвечает метод has
:
const filled = new Set([1, 2, 3, '3', 3, 'hello'])console.log(filled.has(3))// trueconsole.log(filled.has('3'))// trueconsole.log(filled.has('My name'))//false
const filled = new Set([1, 2, 3, '3', 3, 'hello']) console.log(filled.has(3)) // true console.log(filled.has('3')) // true console.log(filled.has('My name')) //false
Полностью очистить Set
можно методом clear
. Технически это то же самое, что и создать новый Set
:
const filled = new Set([1, 2, 3, 3, 3, 'hello'])filled.clear()console.log(filled.size)// 0
const filled = new Set([1, 2, 3, 3, 3, 'hello']) filled.clear() console.log(filled.size) // 0
Обход
Секция статьи "Обход"Set
— это неиндексированная коллекция. В этой структуре данных нет понятия индекса элемента, поэтому нельзя получить произвольный элемент коллекции. В коллекцию можно только положить значение, а получить отдельное значение нельзя.
Основной инструмент работы с Set
— обход коллекции. При обходе коллекции нам гарантируется, что мы будем получать элементы в порядке их добавления в Set
, то есть первыми обойдём элементы добавленные раньше всего.
Обход можно организовать двумя способами:
1️⃣ Использовать метод forEach
, который работает аналогично одноимённому методу массива:
const filled = new Set([1, 2, 3, 3, 3, 'hello'])filled.forEach(function(value) { console.log(value)})// 1// 2// 3// 'hello'
const filled = new Set([1, 2, 3, 3, 3, 'hello']) filled.forEach(function(value) { console.log(value) }) // 1 // 2 // 3 // 'hello'
2️⃣ Воспользоваться for
:
const filled = new Set([1, 2, 3, 3, 3, 'hello'])for (let n of filled) { console.log(n)}// 1// 2// 3// 'hello'
const filled = new Set([1, 2, 3, 3, 3, 'hello']) for (let n of filled) { console.log(n) } // 1 // 2 // 3 // 'hello'
Особенности работы с непримитивными типами
Секция статьи "Особенности работы с непримитивными типами"Set
использует строгое сравнение для проверки, есть ли элемент в коллекции или нет. Добавление примитивных значений разных типов будет работать как ожидается, приведения типов нет. При добавлении числа и строки с этим числом оба добавятся в коллекцию:
const set = new Set()set.add(1)set.add('1')console.log(set.size)// 2
const set = new Set() set.add(1) set.add('1') console.log(set.size) // 2
Непримитивные типы хранятся по ссылке, поэтому Set
будет проверять что мы действительно пытаемся добавить тот же самый объект в коллекцию или нет. Это может казаться нелогичным, потому что объекты могут выглядеть одинаково, но не быть одним и тем же объектом (то есть у них разные адреса в памяти):
Создадим два различных объекта с одинаковым набором свойств. Сравним их друг с другом и с собой:
const cheapShirt = { size: 'L', color: 'white' }const fancyShirt = { size: 'L', color: 'white' }console.log(cheapShirt === fancyShirt)// falseconsole.log(cheapShirt === cheapShirt)// trueconsole.log(fancyShirt === fancyShirt)// true
const cheapShirt = { size: 'L', color: 'white' } const fancyShirt = { size: 'L', color: 'white' } console.log(cheapShirt === fancyShirt) // false console.log(cheapShirt === cheapShirt) // true console.log(fancyShirt === fancyShirt) // true
Мы создали два разных объекта (фигурные скобки создают новый объект), которые выглядят одинаково, но по факту это разные объекты. Они не равны друг другу — если в один добавить новое свойство, то второй не изменится.
Попробуем добавить эти объекты в Set
:
const closet = new Set()closet.add(cheapShirt)closet.add(fancyShirt)console.log(closet.size)// 2
const closet = new Set() closet.add(cheapShirt) closet.add(fancyShirt) console.log(closet.size) // 2
Так как это разные объекты, то оба добавились в коллекцию. Если же попробовать добавить их второй раз, то эта операция будет проигнорирована:
const closet = new Set()closet.add(cheapShirt)closet.add(fancyShirt)console.log(closet.size)// 2closet.add(cheapShirt)closet.add(cheapShirt)closet.add(fancyShirt)console.log(closet.size)// 2
const closet = new Set() closet.add(cheapShirt) closet.add(fancyShirt) console.log(closet.size) // 2 closet.add(cheapShirt) closet.add(cheapShirt) closet.add(fancyShirt) console.log(closet.size) // 2
На практике
Секция статьи "На практике"🛠 С помощью Set
можно легко получить массив уникальных элементов из массива неуникальных с помощью конструктора и spread-оператора:
const nonUnique = [1, 2, 3, 4, 5, 4, 5, 1, 1]const uniqueValuesArr = [...new Set(nonUnique)]console.log(uniqueValuesArr)// [1, 2, 3, 4, 5]
const nonUnique = [1, 2, 3, 4, 5, 4, 5, 1, 1] const uniqueValuesArr = [...new Set(nonUnique)] console.log(uniqueValuesArr) // [1, 2, 3, 4, 5]
Это не самый оптимальный способ преобразования с точки зрения скорости работы, но самый удобный с точки зрения количества кода.