The Set collection
In the lesson on Map the cloakroom stored "token — coat" pairs. Sometimes you need no pair, and only one thing matters: has this guest come already? Picture a guard at the door with a guest list. They write each name down once, and to the question "Has Anna arrived?" they answer by looking at the list.
In an array you have to keep such a list by hand: check includes before every push. The built-in collection Set makes this check by itself. The expression new Set() creates an empty collection:
const tags = new Set();
tags.add("js");
tags.add("css");
tags.add("js");
console.log(tags.size); // 2
console.log(tags.has("css"), tags.has("html")); // true falseLet's go step by step:
new Set()creates the empty collectiontags.- The first two
addcalls store"js"and"css". - The third
addwith"js"changes nothing: that value is already there. - That is why
sizeis2. has("css")givestrue, andhas("html")givesfalse.
What a Set can do
A Set stores separate values, without keys, and holds each value only once. Calling add again with the same value changes nothing.
A Set has:
- the method
has, which tells whether a value is in the collection; - the method
delete, which removes a value; - the property
size, which holds the number of values.
Unlike includes on an array, has does not go through the values one by one. So a large collection is checked faster. The guard, too, does not read the whole list from the top but goes straight to the right line.
Such a collection fits when only one thing matters: whether a value has occurred before. Examples are visited pages, issued numbers or the tags of an article.
Which values are equal
A Set compares values the same way as the === operator. The number 3 and the string "3" are different for it, so both stay. There is one difference from ===: NaN === NaN gives false, but a Set counts two NaN values as one value.
Objects are compared by reference, and two objects with the same properties are two different values:
const values = new Set([3, "3", 3, NaN, NaN]);
console.log(values.size); // 3
const points = new Set([{ x: 1 }, { x: 1 }]);
console.log(points.size); // 2The expression new Set(arr) with an array inside adds its elements one by one, as if add were called for each. That is why repeats from the array do not reach the collection:
valueskeeps3,"3"and oneNaN, three values in all;pointsholds two different objects, although their properties are the same.
This is where the guest-list analogy stops working. The guard would recognize two guests with one name and write down one. A Set of objects looks not at the properties but at the object itself: two { x: 1 } literals create two different objects.
An array without repeats
A Set remembers the order of adding, and a for…of loop goes over the values in that order. Spread syntax turns a Set back into an array. Together, new Set and spread syntax give an array without repeats. Each value stands where it first occurred, and the repeats disappear:
const nums = [3, 1, 3, 2, 1];
const seen = new Set(nums);
for (const n of seen) {
console.log(n);
}
// 3
// 1
// 2
console.log([...seen].join(" ")); // 3 1 2The original array nums does not change: new Set(nums) only reads its elements.
Interviewers like to ask about this trick: "How do you remove repeats from an array in one line?" The answer is [...new Set(nums)].
Common mistake
A value of a Set was read by index, like an array element:
const seen = new Set(["a", "b"]);
console.log(seen[0]); // ✗The program prints undefined. A Set has an order but no indexes, and seen.length gives undefined too. A Set exists to check quickly whether a value is in it, not to take values by position. To take a value by its position, turn the Set into an array first: [...seen][0] gives "a".
Key points
- A
Setholds each value once: a repeatedaddchanges nothing. haschecks whether a value is there, andsizeholds the number of values.- Values are compared as with
===, except that twoNaNvalues count as one, and objects are compared by reference. [...new Set(nums)]gives an array without repeats, in the order of first appearance.
Subscribe to take the course
The course is free. Sign in with Telegram and subscribe to the channel to open every lesson.