JavaScript Set – Working with Unique Collections

The Set object in JavaScript is a powerful data structure that lets you store unique values of any type. Whether you’re working with arrays, removing duplicates, or managing collections, understanding Set is essential for modern JavaScript development.

Contents

What is a Set?

A Set is a collection of values where each value can occur only once. It can hold any type of value, whether primitive (like numbers or strings) or object references.

const mySet = new Set();
mySet.add(1);
mySet.add("hello");
mySet.add({x: 10});
mySet.add(1);  // This won't add a duplicate

console.log(mySet.size);  // 3

Creating Sets

There are multiple ways to create a Set:

Empty Set

const emptySet = new Set();

From an Array

const arraySet = new Set([1, 2, 3, 2, 1]);
console.log([...arraySet]);  // [1, 2, 3]

// Great for removing duplicates from arrays
const uniqueArray = [...new Set([1, 2, 2, 3, 3, 4])];
console.log(uniqueArray);  // [1, 2, 3, 4]

From a String

const stringSet = new Set('hello');
console.log([...stringSet]);  // ['h', 'e', 'l', 'o']

Basic Set Operations

Adding Elements

Use the add() method to insert elements:

const colors = new Set();
colors.add('red');
colors.add('blue').add('green');  // Method chaining works

// Adding different types
colors.add(42);
colors.add({shade: 'dark'});

Removing Elements

Remove elements using delete():

const numbers = new Set([1, 2, 3, 4]);
numbers.delete(2);  // Returns true
numbers.delete(5);  // Returns false (element didn't exist)

// Remove all elements
numbers.clear();
console.log(numbers.size);  // 0

Checking for Elements

Use has() to check if an element exists:

const fruits = new Set(['apple', 'banana', 'orange']);
console.log(fruits.has('apple'));   // true
console.log(fruits.has('mango'));   // false

Iterating Over Sets

Sets are iterable and support various methods for traversing elements.

Using for…of

const pets = new Set(['cat', 'dog', 'hamster']);

for (const pet of pets) {
    console.log(pet);
}

Using forEach

const numbers = new Set([1, 2, 3]);
numbers.forEach((value, valueAgain, set) => {
    console.log(value);  // Note: valueAgain is the same as value
});

Set Iterator Methods

Sets provide three iterator methods:

const colors = new Set(['red', 'green', 'blue']);

// values() returns an iterator of values
console.log([...colors.values()]);  // ['red', 'green', 'blue']

// keys() is the same as values() in a Set
console.log([...colors.keys()]);    // ['red', 'green', 'blue']

// entries() returns [value, value] pairs to mirror Map's behavior
console.log([...colors.entries()]);  // [['red', 'red'], ['green', 'green'], ['blue', 'blue']]

Set Operations with Arrays

Converting Between Sets and Arrays

// Array to Set
const array = [1, 2, 3, 2, 1];
const set = new Set(array);

// Set to Array
const newArray = [...set];
// or
const alsoArray = Array.from(set);

Set Operations Using Arrays

// Union
const union = new Set([...set1, ...set2]);

// Intersection
const intersection = new Set([...set1].filter(x => set2.has(x)));

// Difference
const difference = new Set([...set1].filter(x => !set2.has(x)));

Advanced Use Cases

Removing Duplicates from Arrays of Objects

const objects = [
    {id: 1, name: 'John'},
    {id: 2, name: 'Jane'},
    {id: 1, name: 'John'}  // Duplicate
];

const uniqueObjects = [
    ...new Set(objects.map(obj => JSON.stringify(obj)))
].map(str => JSON.parse(str));

Using Sets for Efficient Lookup

const allowedUsers = new Set(['user1', 'user2', 'admin']);

function checkAccess(username) {
    return allowedUsers.has(username);
}

console.log(checkAccess('admin'));     // true
console.log(checkAccess('hacker'));    // false

Performance Considerations

  1. Set lookups (has()) are generally faster than array includes()
  2. Sets automatically handle duplicates, saving manual checks
  3. Sets can be more memory-efficient when storing unique values
  4. Converting between Sets and Arrays has a performance cost

Best Practices

  1. Use Sets when you need to maintain a collection of unique values
  2. Choose Sets over Arrays when frequently checking for value existence
  3. Consider using Sets for temporary duplicate removal
  4. Remember that Sets preserve insertion order
  5. Use appropriate type coercion awareness:
const mySet = new Set();
mySet.add(42);
console.log(mySet.has('42'));  // false - no type coercion

Common Gotchas

Object References

const set = new Set();
set.add({x: 1});
set.add({x: 1});
console.log(set.size);  // 2 - objects are distinct references

NaN Equality

const set = new Set();
set.add(NaN);
set.add(NaN);
console.log(set.size);  // 1 - NaN is considered equal to itself in Sets

Conclusion

JavaScript Sets are invaluable when working with unique values and provide excellent performance characteristics for membership testing. Whether you’re removing duplicates, managing collections, or implementing algorithms, Sets offer a robust and efficient solution.

Remember that Sets are best used when:

  • You need to maintain unique values
  • You frequently check for value existence
  • You want to eliminate duplicates efficiently
  • You need to implement mathematical set operations

Keep this guide handy as a reference when working with Sets in your JavaScript projects!