Skip to content
Topic 14 of 16
Theory

Map and Set

Why it matters

Objects and arrays cover most tasks, but not all. Sometimes you need a dictionary whose keys can be more than strings, or fast counting matters. And sometimes you need a collection without repeats: unique visitors, a list of tags, checking "have we seen this before". JavaScript has two collections for this — Map and Set.

Set — a collection of unique values

const tags = new Set();
tags.add("js");
tags.add("css");
tags.add("js");          // a repeat — ignored
console.log(tags.size);
console.log(tags.has("css"));
tags.delete("css");
console.log([...tags]);

Output:

2
true
["js"]

A Set can be created straight from an array — the repeats disappear:

const visits = ["Anna", "Timur", "Anna", "Ira", "Timur"];
const people = new Set(visits);
console.log(people.size);
console.log([...people]);

Output:

3
["Anna","Timur","Ira"]

[...set] turns the set back into an array. The order is the order in which values were added.

Looping over a Set

for (const tag of new Set(["a", "b"])) {
  console.log(tag);
}

Output:

a
b

Map — a dictionary

A Map stores "key → value" pairs, like an object, but:

  • the key can be anything: a number, an object, even a function (an object's keys are only strings);
  • the size is the size property;
  • there are no "built-in" keys like constructor that every object has;
  • the key order always equals the insertion order.
const stock = new Map();
stock.set("apple", 10);
stock.set("pear", 4);
stock.set("apple", 12);           // overwrite
console.log(stock.get("apple"));
console.log(stock.get("plum"));   // no such key
console.log(stock.has("pear"), stock.size);
stock.delete("pear");
console.log([...stock]);

Output:

12
undefined
true 2
[["apple",12]]

A Map can be created straight from an array of pairs: new Map([["a", 1], ["b", 2]]).

Looping over a Map

const prices = new Map([["tea", 50], ["coffee", 90]]);
for (const [name, price] of prices) {
  console.log(`${name}: ${price}`);
}
console.log([...prices.keys()], [...prices.values()]);

Output:

tea: 50
coffee: 90
["tea","coffee"] [50,90]

Each Map element in a loop is a [key, value] pair, handy to unpack with destructuring.

Object ↔ Map

const obj = { a: 1, b: 2 };
const map = new Map(Object.entries(obj));
const back = Object.fromEntries(map);
console.log(map.get("b"), back);

Output:

2 {"a":1,"b":2}

What to choose?

Task Use
Describing one thing (a user, a product) an object {}
A list in order an array []
Counting, a dictionary with arbitrary keys, frequent adds/deletes Map
Uniqueness, a fast "is it there" check Set

How it works inside

Set and Map are built as a hash table: from the key's value the place to look for it is computed immediately. So set.has(x) works instantly even for a million elements. array.includes(x) goes through the array from the start — for a big array and many checks that's thousands of times slower. If in a loop you check "is the element in another array", first make a Set from that array.

Uniqueness in a Set is checked like === (except NaN, which is considered equal to itself). So two different objects { a: 1 } both stay in a Set — they're different references.

Common mistakes

  1. Square brackets for a Map. map["a"] = 1 creates an ordinary property, not a Map element: map.get("a") returns undefined. Use set and get.
  2. length instead of size. Map and Set have size.
  3. Expecting a Set to remove equal objects. new Set([{a: 1}, {a: 1}]).size → 2.
  4. Forgot to convert to an array. A Set has no map or filter — first [...set].
  5. includes in a loop over big arrays. Slow. Make a Set and use has.

Cheat sheet

Set Map
new Set(arr) new Map([[k, v], …])
s.add(x) m.set(k, v)
s.has(x) m.has(k), m.get(k)
s.delete(x) m.delete(k)
s.size m.size
[...s] — to an array [...m] — an array of pairs
for (const x of s) for (const [k, v] of m)

No repeats

Easy+10 XP

Write a function unique(items) that returns a new array without repeated values, in the order of first appearance.

unique([1, 2, 2, 3, 1])     → [1, 2, 3]
unique(["a", "b", "a"])     → ["a", "b"]

Connect the connector to solve tasks

Task code runs on your own computer — faster and more reliable than in the browser. This needs the free CodeWithMe connector app. You only connect it once.

Looking for the connector on this computer…

  1. 1
    Download the connector for your system (Windows, macOS or Linux).Download the connectorOn the download page pick the file with your system in its name, e.g. windows-amd64.
  2. 2Run it and choose a folder for your solutions. It will install Python and Node.js there by itself when needed.
  3. 3
    Enter below the 6-digit code shown in the connector window (“Code for CodeWithMe”). If the browser asks about local network access — allow it.

The connector is open source (on GitHub), works only on your computer and runs code only after you enter the pairing code.