Sets in JavaScript - Unique Values Only! 🎯

Author
Code Index
Published on
November 26, 2024
Reading time
13 min read
Category
Dsa
Sets in JavaScript - Unique Values Only! 🎯

Sets in JavaScript - Unique Values Only! 🎯

A Story to Start With...

Imagine you're collecting stickers for your sticker album. You have a rule: No duplicates allowed! If you already have a sticker, you don't add it again.

Your sticker collection:
🐶 Dog
🐱 Cat
🐰 Rabbit
🐶 Dog  ← Already have this! Don't add!
🦊 Fox
🐱 Cat  ← Already have this! Don't add!

This is exactly what a Set does! It's a collection that automatically removes duplicates! 🎉

What is a Set? (The Super Simple Version)

A Set is like a special box that only keeps one of each thing:

const mySet = new Set([1, 2, 3, 2, 1, 4]);
console.log(mySet); // Set { 1, 2, 3, 4 }
// Notice: Duplicates (2, 1) were automatically removed!

Key Features:

  • No duplicates - Each value appears only once
  • Any type - Can store numbers, strings, objects, anything!
  • Fast lookups - Checking if something exists is super quick
  • Maintains insertion order - Remembers the order you added things

Creating Sets (Different Ways!)

Way 1: Empty Set

const mySet = new Set();
console.log(mySet); // Set {}
console.log(mySet.size); // 0

Way 2: From an Array

const numbers = [1, 2, 3, 2, 1, 4];
const uniqueNumbers = new Set(numbers);

console.log(uniqueNumbers); // Set { 1, 2, 3, 4 }

Way 3: From a String

const word = "HELLO";
const uniqueLetters = new Set(word);

console.log(uniqueLetters); // Set { "H", "E", "L", "O" }
// Notice: Only one "L" even though there are two in "HELLO"

Way 4: With Initial Values

const fruits = new Set(["apple", "banana", "orange"]);
console.log(fruits); // Set { "apple", "banana", "orange" }

Essential Set Methods! 🛠️

1. add() - Add a Value

const colors = new Set();

colors.add("red");
colors.add("blue");
colors.add("green");
colors.add("red"); // Already exists, won't be added!

console.log(colors); // Set { "red", "blue", "green" }
console.log(colors.size); // 3 (not 4!)

Real-life example: Tracking unique visitors!

const visitors = new Set();

function recordVisit(userId) {
  visitors.add(userId);
  console.log(`Total unique visitors: ${visitors.size}`);
}

recordVisit("user123"); // Total unique visitors: 1
recordVisit("user456"); // Total unique visitors: 2
recordVisit("user123"); // Total unique visitors: 2 (already counted!)

2. has() - Check if Value Exists

const fruits = new Set(["apple", "banana", "orange"]);

console.log(fruits.has("apple")); // true
console.log(fruits.has("grape")); // false

Real-life example: Check if user already voted!

const voters = new Set();

function vote(userId) {
  if (voters.has(userId)) {
    console.log("You already voted!");
    return false;
  }

  voters.add(userId);
  console.log("Vote recorded!");
  return true;
}

vote("user123"); // Vote recorded!
vote("user123"); // You already voted!

3. delete() - Remove a Value

const numbers = new Set([1, 2, 3, 4, 5]);

numbers.delete(3);
console.log(numbers); // Set { 1, 2, 4, 5 }

// Returns true if deleted, false if not found
console.log(numbers.delete(3)); // false (already deleted)
console.log(numbers.delete(4)); // true (successfully deleted)

4. clear() - Remove All Values

const colors = new Set(["red", "blue", "green"]);
console.log(colors.size); // 3

colors.clear();
console.log(colors.size); // 0
console.log(colors); // Set {}

5. size - Get Number of Values

const fruits = new Set(["apple", "banana", "orange"]);

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

fruits.add("grape");
console.log(fruits.size); // 4

fruits.delete("apple");
console.log(fruits.size); // 3

Looping Through Sets

Method 1: for...of Loop

const fruits = new Set(["apple", "banana", "orange"]);

for (let fruit of fruits) {
  console.log(fruit);
}
// apple
// banana
// orange

Method 2: forEach()

const numbers = new Set([1, 2, 3, 4, 5]);

numbers.forEach((num) => {
  console.log(num * 2);
});
// 2
// 4
// 6
// 8
// 10

Method 3: Convert to Array

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

// Convert to array
const colorArray = [...colors];
console.log(colorArray); // ["red", "blue", "green"]

// Now you can use array methods!
const upperColors = colorArray.map((color) => color.toUpperCase());
console.log(upperColors); // ["RED", "BLUE", "GREEN"]

Sets vs Arrays - When to Use What?

Use Arrays When:

  • ✅ You need duplicates
  • ✅ You need to access by index (arr[0])
  • ✅ Order matters and you need to sort
  • ✅ You need array methods (map, filter, reduce)
const scores = [95, 87, 92, 87, 88]; // Duplicates are meaningful!
const fruits = ["apple", "banana", "orange"];
console.log(fruits[1]); // "banana" (access by index)

Use Sets When:

  • ✅ You need unique values only
  • ✅ You need fast lookups (has())
  • ✅ You're removing duplicates
  • ✅ You're checking membership
const uniqueVisitors = new Set(); // Only unique visitors
const tags = new Set(["js", "react", "node"]); // No duplicate tags

Common Set Operations

1. Remove Duplicates from Array

function removeDuplicates(arr) {
  return [...new Set(arr)];
}

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

const words = ["hello", "world", "hello", "javascript"];
console.log(removeDuplicates(words));
// ["hello", "world", "javascript"]

2. Union - Combine Two Sets

function union(setA, setB) {
  return new Set([...setA, ...setB]);
}

const set1 = new Set([1, 2, 3]);
const set2 = new Set([3, 4, 5]);

console.log(union(set1, set2)); // Set { 1, 2, 3, 4, 5 }

Real-life example: Combine friend lists!

const myFriends = new Set(["Alice", "Bob", "Charlie"]);
const yourFriends = new Set(["Charlie", "David", "Eve"]);

const allFriends = union(myFriends, yourFriends);
console.log(allFriends);
// Set { "Alice", "Bob", "Charlie", "David", "Eve" }

3. Intersection - Find Common Values

function intersection(setA, setB) {
  return new Set([...setA].filter((x) => setB.has(x)));
}

const set1 = new Set([1, 2, 3, 4]);
const set2 = new Set([3, 4, 5, 6]);

console.log(intersection(set1, set2)); // Set { 3, 4 }

Real-life example: Find mutual friends!

const myFriends = new Set(["Alice", "Bob", "Charlie"]);
const yourFriends = new Set(["Charlie", "David", "Alice"]);

const mutualFriends = intersection(myFriends, yourFriends);
console.log(mutualFriends); // Set { "Alice", "Charlie" }

4. Difference - Find Values Only in First Set

function difference(setA, setB) {
  return new Set([...setA].filter((x) => !setB.has(x)));
}

const set1 = new Set([1, 2, 3, 4]);
const set2 = new Set([3, 4, 5, 6]);

console.log(difference(set1, set2)); // Set { 1, 2 }

Real-life example: Find friends only you have!

const myFriends = new Set(["Alice", "Bob", "Charlie"]);
const yourFriends = new Set(["Charlie", "David"]);

const onlyMyFriends = difference(myFriends, yourFriends);
console.log(onlyMyFriends); // Set { "Alice", "Bob" }

5. Symmetric Difference - Values in Either But Not Both

function symmetricDifference(setA, setB) {
  const diff1 = difference(setA, setB);
  const diff2 = difference(setB, setA);
  return union(diff1, diff2);
}

const set1 = new Set([1, 2, 3, 4]);
const set2 = new Set([3, 4, 5, 6]);

console.log(symmetricDifference(set1, set2)); // Set { 1, 2, 5, 6 }

Common Set Patterns (Interview Favorites!)

Pattern 1: Count Unique Elements

function countUnique(arr) {
  return new Set(arr).size;
}

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

const letters = "HELLO".split("");
console.log(countUnique(letters)); // 4 (H, E, L, O)

Pattern 2: Check if All Elements are Unique

function hasAllUnique(arr) {
  return arr.length === new Set(arr).size;
}

console.log(hasAllUnique([1, 2, 3, 4])); // true
console.log(hasAllUnique([1, 2, 2, 3])); // false

Pattern 3: Find Missing Number

function findMissing(arr, n) {
  const set = new Set(arr);

  for (let i = 1; i <= n; i++) {
    if (!set.has(i)) {
      return i;
    }
  }

  return null;
}

const numbers = [1, 2, 4, 5, 6]; // Missing 3
console.log(findMissing(numbers, 6)); // 3

Pattern 4: Longest Substring Without Repeating Characters

function longestUniqueSubstring(str) {
  let maxLength = 0;
  let start = 0;
  const seen = new Set();

  for (let end = 0; end < str.length; end++) {
    while (seen.has(str[end])) {
      seen.delete(str[start]);
      start++;
    }

    seen.add(str[end]);
    maxLength = Math.max(maxLength, end - start + 1);
  }

  return maxLength;
}

console.log(longestUniqueSubstring("abcabcbb")); // 3 ("abc")
console.log(longestUniqueSubstring("bbbbb")); // 1 ("b")
console.log(longestUniqueSubstring("pwwkew")); // 3 ("wke")

Pattern 5: Contains Duplicate

function containsDuplicate(arr) {
  return arr.length !== new Set(arr).size;
}

console.log(containsDuplicate([1, 2, 3, 4])); // false
console.log(containsDuplicate([1, 2, 3, 1])); // true

Practice Challenges! 🎮

Challenge 1: Find First Duplicate

Find the first number that appears twice!

function firstDuplicate(arr) {
  // Your code here!
  // Hint: Use a Set to track what you've seen!
}

console.log(firstDuplicate([2, 1, 3, 5, 3, 2])); // 3
console.log(firstDuplicate([1, 2, 3, 4])); // null
Click to see the answer!
function firstDuplicate(arr) {
  const seen = new Set();

  for (let num of arr) {
    if (seen.has(num)) {
      return num; // Found first duplicate!
    }
    seen.add(num);
  }

  return null; // No duplicates
}

Challenge 2: Is Subset

Check if setA is a subset of setB (all values in setA are in setB)!

function isSubset(setA, setB) {
  // Your code here!
  // Hint: Check if every value in setA exists in setB!
}

const set1 = new Set([1, 2]);
const set2 = new Set([1, 2, 3, 4]);

console.log(isSubset(set1, set2)); // true
console.log(isSubset(set2, set1)); // false
Click to see the answer!
function isSubset(setA, setB) {
  for (let value of setA) {
    if (!setB.has(value)) {
      return false;
    }
  }
  return true;
}

// Or using every:
function isSubset(setA, setB) {
  return [...setA].every((value) => setB.has(value));
}

Challenge 3: Unique Characters

Check if a string has all unique characters!

function hasUniqueChars(str) {
  // Your code here!
  // Hint: Compare string length with Set size!
}

console.log(hasUniqueChars("abcdef")); // true
console.log(hasUniqueChars("hello")); // false (two 'l's)
Click to see the answer!
function hasUniqueChars(str) {
  return str.length === new Set(str).size;
}

// Or more explicit:
function hasUniqueChars(str) {
  const seen = new Set();

  for (let char of str) {
    if (seen.has(char)) {
      return false;
    }
    seen.add(char);
  }

  return true;
}

Challenge 4: Common Elements in Arrays

Find elements that appear in all arrays!

function commonElements(...arrays) {
  // Your code here!
  // Hint: Use intersection on all arrays!
}

console.log(commonElements([1, 2, 3], [2, 3, 4], [2, 3, 5]));
// [2, 3]
Click to see the answer!
function commonElements(...arrays) {
  if (arrays.length === 0) return [];

  // Start with first array as a Set
  let result = new Set(arrays[0]);

  // Intersect with each subsequent array
  for (let i = 1; i < arrays.length; i++) {
    const currentSet = new Set(arrays[i]);
    result = new Set([...result].filter((x) => currentSet.has(x)));
  }

  return [...result];
}

Challenge 5: Remove Elements

Remove all instances of specific values from an array!

function removeElements(arr, toRemove) {
  // Your code here!
  // Hint: Use a Set for fast lookup!
}

const numbers = [1, 2, 3, 4, 5, 2, 3];
const remove = [2, 3];

console.log(removeElements(numbers, remove)); // [1, 4, 5]
Click to see the answer!
function removeElements(arr, toRemove) {
  const removeSet = new Set(toRemove);
  return arr.filter((item) => !removeSet.has(item));
}

Performance Comparison ⚡

Set vs Array for Lookups

// Array - O(n) - slow for large arrays
const bigArray = Array.from({ length: 1000000 }, (_, i) => i);
console.time("Array lookup");
bigArray.includes(999999); // Has to check every item!
console.timeEnd("Array lookup");

// Set - O(1) - instant!
const bigSet = new Set(bigArray);
console.time("Set lookup");
bigSet.has(999999); // Instant!
console.timeEnd("Set lookup");

// Set is MUCH faster! ⚡

When Sets are Faster

OperationArraySet
AddO(1)O(1)
RemoveO(n)O(1)
SearchO(n)O(1)
Access by indexO(1)❌ Not possible

Common Mistakes to Avoid! ⚠️

Mistake 1: Trying to Access by Index

// ❌ Wrong - Sets don't have indexes!
const mySet = new Set([1, 2, 3]);
console.log(mySet[0]); // undefined

// ✅ Right - convert to array first
const arr = [...mySet];
console.log(arr[0]); // 1

Mistake 2: Forgetting Sets Use Reference Equality for Objects

// ❌ Wrong - objects are compared by reference
const set = new Set();
set.add({ name: "Sarah" });
set.add({ name: "Sarah" }); // Different object!
console.log(set.size); // 2 (not 1!)

// ✅ Right - use same reference
const person = { name: "Sarah" };
const set2 = new Set();
set2.add(person);
set2.add(person); // Same object!
console.log(set2.size); // 1

Mistake 3: Modifying While Iterating

// ❌ Wrong - don't modify while looping
const set = new Set([1, 2, 3]);
for (let num of set) {
  set.delete(num); // Dangerous!
}

// ✅ Right - convert to array first
const set2 = new Set([1, 2, 3]);
[...set2].forEach((num) => set2.delete(num));

Key Takeaways! 🎯

  1. Sets store unique values - No duplicates allowed!
  2. Fast lookups - has() is O(1), much faster than array includes()
  3. Any type - Can store numbers, strings, objects, anything
  4. Maintains order - Remembers insertion order
  5. Great for removing duplicates - [...new Set(arr)]
  6. Set operations - Union, intersection, difference

Quick Reference Card 📋

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

// Adding
set.add(value)

// Checking
set.has(value)      // true/false
set.size            // number of values

// Removing
set.delete(value)   // remove one
set.clear()         // remove all

// Looping
for (let val of set) { }
set.forEach(val => { })

// Converting
[...set]            // to array
new Set(array)      // from array

// Operations
union(setA, setB)
intersection(setA, setB)
difference(setA, setB)

// Common patterns
new Set(arr).size           // count unique
arr.length === new Set(arr).size  // all unique?
[...new Set(arr)]           // remove duplicates

What's Next?

Congratulations! 🎉 You've completed the Beginner Track of the DSA series!

You now understand:

  • ✅ Arrays
  • ✅ Strings
  • ✅ Objects & Hash Maps
  • ✅ Sets

In the next episode, we'll start the Intermediate Track with Stacks & Queues - special data structures with specific rules!

We'll cover:

  • What Stacks and Queues are
  • How to implement them
  • When to use each one
  • Real-world applications
  • Common interview problems

This is Episode 5 of the "Mastering DSA with JavaScript" series.

Previous Episode: Objects & Hash Maps →

Next Episode: Stacks & Queues - LIFO and FIFO Explained! →

Questions? Drop a comment below! 💬