Deduplicating an array takes one line, provided you know the right structure. Without it, people write a nested loop comparing every element with every other one, and the cost explodes past a few thousand entries.
Set settles that case and another one, just as frequent: telling quickly whether a value has already been seen.
Definition
A Set is a collection of values where each value appears only once. Adding a value already present does nothing, and insertion order is preserved.
const seen = new Set();
seen.add("ada@site.com");
seen.add("ada@site.com");
seen.add("alan@site.com");
console.log(seen.size); // 2
console.log(seen.has("ada@site.com")); // true
seen.delete("alan@site.com");
console.log([...seen]); // [ 'ada@site.com' ]Four methods are enough: add, has, delete and clear. The count is read from size, never from a length property.
Deduplicating an array
This is the most common use, and it fits on one line thanks to Spread (...), which unfolds the Set back into an Array.
const languages = ["fr", "en", "fr", "es", "en"];
const unique = [...new Set(languages)];
console.log(unique); // [ 'fr', 'en', 'es' ]The constructor accepts anything that can be walked, a string included: new Set("hello") holds four letters, the second l having been dropped.
Set or array
| Need | What to reach for |
|---|---|
| Reaching the third value | An array, a Set has no index |
| Testing membership often | A Set, whose has scans nothing |
| Keeping duplicates | An array, by construction |
| Sorting, mapping, filtering | An array, even if a Set comes after |
Converting either way is cheap, which makes the round trip common: you go through a Set to drop the duplicates, then come back to an array to sort or display the result.
Uniqueness applies to the value, and two distinct objects are two different values even when they look alike. new Set([{ x: 1 }, { x: 1 }]).size is 2. To deduplicate objects, pull a key out of them first, an identifier for instance.
Frequently asked questions
Is a Set really faster than an array?
For membership tests, yes, and the gap widens with size: has does not depend on the number of elements, where includes walks the array. Across ten values the difference cannot be measured, across fifty thousand it decides the matter.
How do you intersect two collections?
The portable way is filtering one array on the other collection's has. Recent engines add union, intersection and difference straight onto Set, worth using only where you control the runtime version.
Can a Set be converted to JSON?
Not directly: as with Map objects, JSON produces an empty object. Unfold it into an array first, with JSON.stringify([...mySet]), and rebuild a Set when reading it back.