Sets and Maps – Using New Data Structures
With the introduction of ES6 (ECMAScript 2015), Sets and Maps were introduced as new data structures in JavaScript. These provide efficient ways to work with collections of values or key-value pairs. In this article, we will explain the basics of Sets and Maps, show their advantages, and demonstrate with code examples how they can be used in practice.
What are Sets?
A Set is a collection of unique values. This means that a Set contains no duplicate elements. Sets can store values of any type – be it primitive data types or objects.
Creating a Set
// Create empty Set
const mySet = new Set();
// Create Set with initial values
const numberSet = new Set([1, 2, 3, 4, 5]);
Adding and Removing Elements
const mySet = new Set();
mySet.add(1);
mySet.add(2);
mySet.add(2); // Duplicate values are ignored
console.log(mySet); // Set { 1, 2 }
mySet.delete(1);
console.log(mySet); // Set { 2 }
Checking for Element Presence
const mySet = new Set([1, 2, 3]);
console.log(mySet.has(2)); // true
console.log(mySet.has(4)); // false
Iterating Over a Set
const mySet = new Set(['a', 'b', 'c']);
for (let item of mySet) {
console.log(item);
}
// Output:
// 'a'
// 'b'
// 'c'
Application Example: Removing Duplicates from an Array
const numbers = [1, 2, 2, 3, 4, 4, 5];
const uniqueNumbers = [...new Set(numbers)];
console.log(uniqueNumbers); // [1, 2, 3, 4, 5]
What are Maps?
A Map is a collection of key-value pairs. Unlike regular objects, Maps can have keys of any type, not just strings.
Creating a Map
// Create empty Map
const myMap = new Map();
// Create Map with initial values
const fruitMap = new Map([
['Apple', 1],
['Banana', 2],
['Orange', 3]
]);
Adding and Removing Entries
const myMap = new Map();
myMap.set('Name', 'Max');
myMap.set('Age', 28);
console.log(myMap);
// Map { 'Name' => 'Max', 'Age' => 28 }
myMap.delete('Age');
console.log(myMap);
// Map { 'Name' => 'Max' }
Accessing Values
const myMap = new Map();
myMap.set('Key', 'Value');
console.log(myMap.get('Key')); // 'Value'
console.log(myMap.has('Key')); // true
Iterating Over a Map
const myMap = new Map();
myMap.set('a', 1);
myMap.set('b', 2);
for (let [key, value] of myMap) {
console.log(`${key}: ${value}`);
}
// Output:
// 'a: 1'
// 'b: 2'
Application Example: Using Objects as Keys
const user1 = { name: 'Anna' };
const user2 = { name: 'Ben' };
const loginCount = new Map();
loginCount.set(user1, 5);
loginCount.set(user2, 3);
console.log(loginCount.get(user1)); // 5
console.log(loginCount.get(user2)); // 3
Advantages of Sets and Maps
Sets
-
Easy Removal of Duplicates from Arrays:
const numbers = [1, 2, 2, 3, 4, 4, 5]; const uniqueNumbers = [...new Set(numbers)]; console.log(uniqueNumbers); // [1, 2, 3, 4, 5] -
Efficient Checking for Element Presence (O(1) Complexity):
const mySet = new Set(['Apple', 'Banana', 'Cherry']); console.log(mySet.has('Banana')); // true, fast query in O(1) console.log(mySet.has('Orange')); // false
Maps
-
Keys Can Be of Any Type (Not Just Strings):
const objKey = { id: 42 }; const map = new Map(); map.set(objKey, 'Value for an object as key'); map.set(123, 'Value for a number as key'); console.log(map.get(objKey)); // "Value for an object as key" console.log(map.get(123)); // "Value for a number as key" -
Maintain Insertion Order:
const orderedMap = new Map([ ['first', 1], ['second', 2], ['third', 3] ]); for (const [key, value] of orderedMap) { console.log(key, value); } // Output in insertion order: // "first" 1 // "second" 2 // "third" 3 -
Better Performance with Frequent Insertions and Deletions of Key-Value Pairs
Weaknesses and Limitations
Sets
- No Direct Way to Access an Element by Index
- Are Unordered, i.e., Element Order is Not Guaranteed
Maps
-
Not Serializable with JSON.stringify:
const myMap = new Map([['name', 'Anna'], ['age', 25]]); console.log(JSON.stringify(myMap)); // "{}" - Map is not meaningfully serialized // Must explicitly convert: const obj = Object.fromEntries(myMap); console.log(JSON.stringify(obj)); // '{"name":"Anna","age":25}' – now meaningfully serializable -
When Using Only Strings or Symbols as Keys, Regular Objects May Offer a Simpler Alternative
Practical Use Cases
1. Tracking User Activities with Sets
const activeUsers = new Set();
function login(user) {
activeUsers.add(user);
}
function logout(user) {
activeUsers.delete(user);
}
const user1 = { name: 'Max' };
const user2 = { name: 'Lisa' };
login(user1);
login(user2);
console.log(activeUsers.size); // 2
logout(user1);
console.log(activeUsers.size); // 1
2. Keyword Counting with Maps
const text = 'Hello World Hello JavaScript World';
const words = text.split(' ');
const wordCount = new Map();
for (let word of words) {
const count = wordCount.get(word) || 0;
wordCount.set(word, count + 1);
}
for (let [word, count] of wordCount) {
console.log(`${word}: ${count}`);
}
// Output:
// 'Hello: 2'
// 'World: 2'
// 'JavaScript: 1'
Conclusion
Sets and Maps are valuable additions to the existing data structures in JavaScript. They provide efficient and flexible ways to work with collections of values and key-value pairs. Through their unique properties, they can complement or even replace traditional arrays and objects in many situations.
Use Sets and Maps in your next project to benefit from their advantages and make your code more efficient and readable!