Map and Set Revisited

In Chapter 02, we introduced Map and Set as alternatives to objects and arrays. Now that you are familiar with arrow functions, iteration, and the spread operator, let’s look at these collections more closely.

Iterating Over Maps

Maps maintain insertion order and provide several ways to iterate over their contents.

Using for…of

const userRoles = new Map([
  ["alice", "admin"],
  ["bob", "editor"],
  ["charlie", "viewer"],
]);

// Iterate over entries (default)
for (const [user, role] of userRoles) {
  console.log(`${user}: ${role}`);
}

// Iterate over keys only
for (const user of userRoles.keys()) {
  console.log(user);
}

// Iterate over values only
for (const role of userRoles.values()) {
  console.log(role);
}

Using forEach

const scores = new Map([
  ["Alice", 95],
  ["Bob", 87],
  ["Charlie", 92],
]);

scores.forEach((score, name) => {
  console.log(`${name} scored ${score}`);
});

The entries() Method

The entries() method returns an iterator of [key, value] pairs:

const map = new Map([
  ["a", 1],
  ["b", 2],
]);

const entries = map.entries();
console.log(entries.next().value); // ["a", 1]
console.log(entries.next().value); // ["b", 2]

Iterating Over Sets

Sets also maintain insertion order and support similar iteration patterns.

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

// for...of
for (const color of colors) {
  console.log(color);
}

// forEach
colors.forEach((color) => {
  console.log(color);
});

Sets also have keys(), values(), and entries() methods. Since Sets only have values (no keys), keys() and values() return the same iterator, and entries() returns [value, value] pairs for consistency with Map.

Converting Between Collections and Arrays

We can convert between collections and arrays with the spread operator or Array.from().

Map to Array

const map = new Map([
  ["name", "Alice"],
  ["age", 30],
]);

// Spread into array of entries
const entries = [...map];
console.log(entries); // [["name", "Alice"], ["age", 30]]

// Get just keys or values
const keys = [...map.keys()]; // ["name", "age"]
const values = [...map.values()]; // ["Alice", 30]

Set to Array

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

// Using spread
const arr1 = [...set]; // [1, 2, 3]

// Using Array.from
const arr2 = Array.from(set); // [1, 2, 3]

Array to Set (Remove Duplicates)

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

Object to Map

const obj = { name: "Alice", age: 30 };
const map = new Map(Object.entries(obj));
console.log(map.get("name")); // "Alice"

Map to Object

const map = new Map([
  ["name", "Alice"],
  ["age", 30],
]);
const obj = Object.fromEntries(map);
console.log(obj); // { name: "Alice", age: 30 }

Set Operations

Sets work well for mathematical set operations. Here are the common ones:

Union

Combine all elements from both sets:

const a = new Set([1, 2, 3]);
const b = new Set([2, 3, 4]);

const union = new Set([...a, ...b]);
console.log([...union]); // [1, 2, 3, 4]

Intersection

Elements that exist in both sets:

const a = new Set([1, 2, 3]);
const b = new Set([2, 3, 4]);

const intersection = new Set([...a].filter((x) => b.has(x)));
console.log([...intersection]); // [2, 3]

Difference

Elements in the first set but not in the second:

const a = new Set([1, 2, 3]);
const b = new Set([2, 3, 4]);

const difference = new Set([...a].filter((x) => !b.has(x)));
console.log([...difference]); // [1]

Symmetric Difference

Elements in either set but not in both:

const a = new Set([1, 2, 3]);
const b = new Set([2, 3, 4]);

const symDiff = new Set([...a, ...b].filter((x) => !(a.has(x) && b.has(x))));
console.log([...symDiff]); // [1, 4]

Practical Example

const subscribedUsers = new Set(["alice", "bob", "charlie"]);
const activeUsers = new Set(["bob", "diana", "eve"]);

// Users who are subscribed AND active
const engagedUsers = new Set(
  [...subscribedUsers].filter((u) => activeUsers.has(u)),
);
console.log([...engagedUsers]); // ["bob"]

// Users who are subscribed but NOT active (churned)
const churnedUsers = new Set(
  [...subscribedUsers].filter((u) => !activeUsers.has(u)),
);
console.log([...churnedUsers]); // ["alice", "charlie"]