Hash Sets in JavaScript


Hash Sets are collections of unique items i.e no element can be repeated.

Hash Sets were designed to give us a way of adding and looking for unique values in a collection in a quick manner.

The values in a Hash Set can be either simple primitives like strings or integers as well as more complex object types like object literals or arrays.

In JavaScript, the Hash Set is implemented as the Set object.


Creation:

To create a new empty Set, you use the following syntax:

let mySet = new Set();

Creating an empty Set takes O(1) time.


Constructing from iterable

The Set constructor also accepts an optional iterable object. If you pass an iterable object to the Set constructor, all the unique elements of the object will be added to the new set:

let elements = [1, '2', 'apple', 1];
let mySet = new Set(elements);

console.log(mySet); // Set {1, '2', 'apple'}

This takes O(n) time, where n is the number of elements in the iterable object.


Adding elements:

To add an element to the set, you use the add() method:

let mySet = new Set(['a', 'b', 'c']);

// Adding new elements:
mySet.add('d');

// Adding an existing element:
mySet.add('a'); // nothing happens

console.log(mySet); // Set {'a', 'b', 'c', 'd'}

The Set first checks if that element already exists and if so, it does nothing and also doesn't raise an error.

Adding an element to a Set takes O(1) time.


Checking if a value exists:

To check if a Set has a specific element, you use the has() method. The has() method returns true if the set contains the element, otherwise, it returns false.

let mySet = new Set(['a', 'b', 'c']);

let exist = mySet.has('a');
console.log(exist); // true

exist = chars.has('z');
console.log(exist); // false

Checking if a value exists in a Set takes O(1) time.


Removing elements:

To delete a specified element from a set, you use the delete() method:

let mySet = new Set(['a', 'b', 'c', 'd']);

// Deleting elements:
mySet.delete('a');

// Deleting a non-existent element:
mySet.delete('z'); // does nothing

console.log(mySet); // Set {'b', 'c', 'd'}

The Set first checks if that key exists and if not, it does nothing and also doesn't raise an error, so it's safe to delete non-existing elements.

Removing an element from a Set takes O(1) time.


Iterating over the Set values:

If we want to iterate over values of the Set, we can use the for loop along with the of operator:

let mySet = new Set(['b', 'c', 'c', 'd']);

for (let val of mySet) {
    console.log(val);
}

// This will print the following:
// b
// c
// d

Iterating over a Set takes O(n) time.


Space Complexity

A Set uses O(n) space, where n is the number of elements existing in the Set.


Assignment
Follow the Coding Tutorial and let's play with some Hash Sets.


Hint
Look at the examples above if you get stuck.


Introduction

In this lesson, we will explore the concept of Hash Sets in JavaScript. Hash Sets are a powerful data structure that allows us to store unique values efficiently. They are particularly useful in scenarios where we need to ensure that no duplicate values are present in a collection. Understanding Hash Sets is crucial for optimizing performance in various programming tasks, such as filtering unique items from a list or checking for the existence of elements.

Understanding the Basics

Before diving into the details, let's understand the fundamental concepts of Hash Sets. A Hash Set is a collection of unique items, meaning no element can be repeated. In JavaScript, the Set object implements the Hash Set. The primary operations we can perform on a Set include adding elements, checking for the existence of elements, and removing elements. Let's start with some simple examples to illustrate these concepts.

Creating a Set

let mySet = new Set();

Creating an empty Set is straightforward and takes constant time, O(1).

Constructing from Iterable

let elements = [1, '2', 'apple', 1];
let mySet = new Set(elements);

console.log(mySet); // Set {1, '2', 'apple'}

When constructing a Set from an iterable, only unique elements are added. This operation takes linear time, O(n), where n is the number of elements in the iterable.

Main Concepts

Now that we have a basic understanding, let's delve into the key concepts and techniques involved in working with Hash Sets.

Adding Elements

let mySet = new Set(['a', 'b', 'c']);

// Adding new elements:
mySet.add('d');

// Adding an existing element:
mySet.add('a'); // nothing happens

console.log(mySet); // Set {'a', 'b', 'c', 'd'}

The add() method allows us to add elements to the Set. If the element already exists, it does nothing. Adding an element takes constant time, O(1).

Checking for Existence

let mySet = new Set(['a', 'b', 'c']);

let exist = mySet.has('a');
console.log(exist); // true

exist = mySet.has('z');
console.log(exist); // false

The has() method checks if a Set contains a specific element. This operation also takes constant time, O(1).

Removing Elements

let mySet = new Set(['a', 'b', 'c', 'd']);

// Deleting elements:
mySet.delete('a');

// Deleting a non-existent element:
mySet.delete('z'); // does nothing

console.log(mySet); // Set {'b', 'c', 'd'}

The delete() method removes a specified element from the Set. If the element does not exist, it does nothing. Removing an element takes constant time, O(1).

Examples and Use Cases

Let's explore some examples and real-world use cases where Hash Sets can be beneficial.

Example 1: Filtering Unique Values

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

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

In this example, we use a Set to filter out duplicate values from an array of numbers.

Example 2: Checking for Duplicates

let items = ['apple', 'banana', 'apple', 'orange'];
let itemSet = new Set();

for (let item of items) {
    if (itemSet.has(item)) {
        console.log(`Duplicate found: ${item}`);
    } else {
        itemSet.add(item);
    }
}

This example demonstrates how to check for duplicate items in an array using a Set.

Common Pitfalls and Best Practices

When working with Hash Sets, it's essential to be aware of common mistakes and follow best practices to write efficient and maintainable code.

Common Pitfalls

Best Practices

Advanced Techniques

Let's explore some advanced techniques related to Hash Sets.

Union of Sets

let setA = new Set([1, 2, 3]);
let setB = new Set([3, 4, 5]);

let unionSet = new Set([...setA, ...setB]);
console.log(unionSet); // Set {1, 2, 3, 4, 5}

This example demonstrates how to create a union of two Sets using the spread operator.

Intersection of Sets

let setA = new Set([1, 2, 3]);
let setB = new Set([3, 4, 5]);

let intersectionSet = new Set([...setA].filter(x => setB.has(x)));
console.log(intersectionSet); // Set {3}

This example shows how to find the intersection of two Sets using the filter() method.

Code Implementation

Here are some well-commented code snippets demonstrating the correct use of Hash Sets in JavaScript.

Example: Adding and Checking Elements

// Create a new Set
let mySet = new Set();

// Add elements to the Set
mySet.add('apple');
mySet.add('banana');
mySet.add('apple'); // Duplicate, will not be added

// Check if elements exist in the Set
console.log(mySet.has('apple')); // true
console.log(mySet.has('orange')); // false

// Output the Set
console.log(mySet); // Set {'apple', 'banana'}

Debugging and Testing

Debugging and testing are crucial aspects of working with Hash Sets. Here are some tips and examples to help you debug and test your code effectively.

Debugging Tips

Testing Example

// Test case: Adding elements to a Set
let testSet = new Set();
testSet.add(1);
testSet.add(2);
testSet.add(1); // Duplicate

console.assert(testSet.size === 2, 'Test failed: Set should contain 2 unique elements');
console.assert(testSet.has(1), 'Test failed: Set should contain 1');
console.assert(testSet.has(2), 'Test failed: Set should contain 2');

Thinking and Problem-Solving Tips

When working with Hash Sets, it's essential to approach problems methodically. Here are some strategies to help you think and solve problems effectively.

Breaking Down Problems

Practice and Improvement

Conclusion

In this lesson, we explored the concept of Hash Sets in JavaScript. We covered the basics, key concepts, examples, common pitfalls, best practices, advanced techniques, and debugging tips. Mastering Hash Sets is essential for writing efficient and optimized code, especially when dealing with unique collections of items. Keep practicing and exploring further applications to enhance your skills.

Additional Resources

For further reading and practice problems related to Hash Sets, check out the following resources: