Your country

Tools that support it use your country for local currency, number formats, units and paper size. Your choice is saved only in this browser.

Type a name or a two-letter code. Use the up and down arrow keys to move through the countries, Enter to choose one and Escape to close.

Data Structures & Algorithms (DSA)  Module 3 – Hashing: maps, sets and hash functions

Hash maps in five standard libraries

Use Python dict, Java HashMap, C++ unordered_map, Go maps and JavaScript Map well: missing keys, iteration order, key rules and the trap of each library.

  • Beginner
  • 25 minutes
  • Examples run with Python 3.14.8, Pyodide 314.0.7, Node.js 24.21.0, quickjs 0.32.0, Java 25, Clang 21.0.0 and Go 1.27.1
  • By MySmartCoPilot
Free core, Pro depth: 10 of 25 minutes free
Free: The same count in two languages · Five libraries side by side · Sets in the five libraries · 3 more sections. With a pass: 2 in-depth parts and 3 interview answers, about 15 minutes.

What you will learn

  • Use dict and set, HashMap and HashSet, unordered_map, Go maps and JavaScript Map and Set idiomatically
  • Pick keys that hash and compare correctly
  • Avoid the common correctness and performance traps
  • Group and count items with a map, then report them in sorted order

Before you start

What you’ll learn · Before you start

What you will learn

  • Use dict and set, HashMap and HashSet, unordered_map, Go maps and JavaScript Map and Set idiomatically
  • Pick keys that hash and compare correctly
  • Avoid the common correctness and performance traps
  • Group and count items with a map, then report them in sorted order

Before you start

On this page

Every mainstream language ships a hash map, and the five covered here, Python’s dict and set, Java’s HashMap and HashSet, C++’s unordered_map and unordered_set, Go’s built-in map and JavaScript’s Map and Set, all give insert, find and delete in O(1) time on average. They differ in four places, and those four cause most of the bugs people write with them: what reading a missing key does, the order in which a loop visits the keys, what may be a key, and how two keys are judged equal. This lesson runs one counting task in two languages, puts the five libraries side by side on those four questions, and names the trap each library is known for.

The same count in two languages

Counting how many roll numbers belong to each branch, given by the first three characters, takes one map from branch code to count and one pass:

Count roll numbers by branch, then print the branches in order

Python · count/branches.py

"""Count roll numbers by branch code (the first three characters) and print the branches in sorted order."""
rolls = ["ECE21004", "CSE21001", "MEC21010", "CSE21007", "ECE21002", "CSE21013", "CIV21003"]

counts = {}
for roll in rolls:
    branch = roll[:3]
    counts[branch] = counts.get(branch, 0) + 1  # get() returns 0 for a branch not seen yet

print("as inserted:", counts)
for branch in sorted(counts):
    print(f"{branch}: {counts[branch]}")

Output

as inserted: {'ECE': 2, 'CSE': 3, 'MEC': 1, 'CIV': 1}
CIV: 1
CSE: 3
ECE: 2
MEC: 1

Recorded with Python 3.14.8 on macOS 26 arm64. To run it yourself: mise exec python@3.14.8 -- python3 branches.py

JavaScript · count/branches.mjs

// Count roll numbers by branch code (the first three characters) and print the branches in sorted order.
const rolls = ['ECE21004', 'CSE21001', 'MEC21010', 'CSE21007', 'ECE21002', 'CSE21013', 'CIV21003'];

const counts = new Map();
for (const roll of rolls) {
  const branch = roll.slice(0, 3);
  counts.set(branch, (counts.get(branch) ?? 0) + 1); // get() returns undefined for a branch not seen yet
}

console.log('as inserted:', [...counts.keys()].join(' '));
for (const branch of [...counts.keys()].sort()) console.log(`${branch}: ${counts.get(branch)}`);

Output

as inserted: ECE CSE MEC CIV
CIV: 1
CSE: 3
ECE: 2
MEC: 1

Recorded with Node.js 24.21.0 on macOS 26 arm64. To run it yourself: mise exec node@24.21.0 -- node branches.mjs

Both programs read a missing branch as zero in one expression, counts.get(branch, 0) in Python and counts.get(branch) ?? 0 in JavaScript, because a plain read of a missing key gives no number in either language. Both maps list the branches in the order they first appeared, ECE before CSE, so both sort the keys before printing.

Five libraries side by side

The same four questions, five standard libraries
Criterion Python dict / setJava HashMap / HashSetC++ unordered_map / setGo mapJavaScript Map / Set
Reading a missing key d[k] raises KeyError; d.get(k) gives Noneget(k) returns nullm[k] inserts a default value; find(k) returns end()m[k] returns the zero valueget(k) returns undefined
Is the key there? k in dcontainsKey(k)contains(k), C++20; or findv, ok := m[k]has(k)
Iteration order dict: insertion order; set: noneNone promisedUnspecifiedUnspecified, different on each loopInsertion order
What a key needs __hash__ and __eq__; built-in mutable types refusedequals and hashCode that agreeA std::hash specialisation and ==A comparable type: no slices, maps or functionsAnything; compared with SameValueZero
When to choose Counter and defaultdict for counting and groupingmerge and getOrDefault for countingreserve before bulk inserts; find for readscomma-ok for presence; sort keys for outputMap, not a plain object, for data keys

Read the first row before writing a lookup in an unfamiliar language: the same expression, m[k], raises an error in Python, quietly inserts in C++, returns 0 in Go and is a different operation altogether on a JavaScript Map. The third row is why the counting programs above sort before they print.

Sets in the five libraries

A set is the same table without values, and each library has one. Python has set and the unchangeable frozenset, which can itself be a key. Java’s HashSet is documented as backed by a HashMap, so it inherits that map’s costs and its lack of order. C++ has unordered_set. JavaScript has Set, with the same insertion order and key comparison as Map. Go has no set type; the usual stand-in is a map[string]struct{}, whose empty struct values take no space at all, or a map[string]bool when reading a missing key as false is convenient.

The trap each library is known for

  • Python: a defaultdict creates an entry for every missing key it is asked about, even in a loop that only reads.
  • Java: comparing two Integer values with == compares objects, so it works for small numbers and then fails.
  • C++: reading with operator[] inserts the key when it is missing, so a loop that only reads can grow the map.
  • Go: a loop over a map visits the keys in a different order each time, so output needs sorted keys.
  • JavaScript: a plain object turns every key into a string, so 1 and "1" become the same key.

Each of these compiles, runs and passes a quick test, which is what makes it dangerous: the map still works, but reports a size that is too large, a comparison that is wrong only for larger numbers, or an order that changes between runs.

Choosing keys that hash and compare correctly

A key must keep its hash for as long as it is stored, so use values that cannot change: strings, numbers and tuples in Python, records or strings in Java, structs of comparable fields in Go. Build composite keys from their parts rather than by gluing strings together, because “AB” + “C” and “A” + “BC” give the same text: a tuple (city, day) in Python, a record in Java, a struct in Go. In C++, std::pair has no standard std::hash, so a pair key needs a hash function of your own. In JavaScript, a Map compares object keys by identity, so two objects with the same contents are two different keys; turn such a key into a string or a number first.

Check yourself

Check yourself

4 questions about this lesson. Every answer and why it is right is on the page, behind “Show the answer”. Your score stays in this browser.

  1. Question 1 of 4 In C++, what does m[k] do when the key k is not in an std::unordered_map m?

    Choose one answer.

    Show the answer to question 1

    Answer: It inserts k with a default value and returns a reference to that value

    operator[] always returns a reference to a value, so for a missing key it first inserts one, value-initialised (0 for an int). at() is the call that throws, and find() is the one that returns end().

  2. Question 2 of 4 Which of these promise to iterate in insertion order?

    Choose every answer that is right.

    Show the answer to question 2

    Answer:

    • Python's dict
    • JavaScript's Map

    Python guarantees insertion order for dict since 3.7, and a JavaScript Map iterates in insertion order. Java's HashMap promises no order, and Go leaves map order unspecified, varying it from loop to loop.

  3. Question 3 of 4 What does this Go program print?

    Read the code, then choose one answer.

    stock := map[string]int{"ink": 0}
    a := stock["pad"]
    _, ok := stock["pad"]
    fmt.Println(a, ok, len(stock))
    Show the answer to question 3

    Answer: 0 false 1

    Reading a missing key returns the zero value, 0, and inserts nothing, so the map still has one entry. The comma-ok form reports false because "pad" is not there.

  4. Question 4 of 4 A Python dict must be keyed by a city and a day number together. Which key is the safest choice?

    Choose one answer.

    Show the answer to question 4

    Answer: The tuple (city, day)

    A tuple of a string and an int is hashable and compares both parts. Lists and dicts are unhashable and refused as keys, and gluing strings can make two different pairs, such as ("Agra", 11) and ("Agra1", 1), the same text.

Each library's trap, reproduced and fixed Pro: opens with a Pro, Premium or Ultimate pass

Every trap in the list above fits in a few lines, and each has a one-line fix. This part runs all five, in Python, Java, C++, Go and JavaScript, with the output recorded, and shows the fix next to the failure.

In this part:

  • Python: get, Counter and the keys a dict refuses
  • Java: == on Integer values, and equals without hashCode
  • C++: operator[] inserts; find and contains do not
  • Go: comma-ok, the zero value and sorted output
  • JavaScript: Map against a plain object
  • The five fixes in one place

6 runnable examples (C++, Go, Java, JavaScript, Python) · about 4 minutes

Opening this part with your pass…

This part opens with any MySmartCoPilot pass.

  • Pro pass · 1 week₹79$2.99
  • 30 days₹179$5.99
  • 1 year₹1,699$45

One payment; a pass never renews. The price shown is the total you pay: no fees or charges are added at checkout.

It also opens every other in-depth part in Learn and every Pro tool. Sales are final, except where the law gives you a right to withdraw, for example in the EU and the UK (refund policy).

Memory, presizing and ordered alternatives, measured Pro: opens with a Pro, Premium or Ultimate pass

A hash map’s convenience has a price in memory and in resizing, and when the order of keys matters it is the wrong structure. This part measures both costs and lists the ordered alternatives in each language.

In this part:

  • How a dict grows, and what an entry costs
  • Presizing: reserve, newHashMap and the rehash count
  • When order matters: the ordered alternatives
  • Practise: group roll numbers by branch
  • Group roll numbers by branch, in sorted order
    • Results of the sample tests

3 runnable examples (C++, Python) · 1 exercise with sample tests · about 4 minutes

Opening this part with your pass…

This part opens with any MySmartCoPilot pass.

  • Pro pass · 1 week₹79$2.99
  • 30 days₹179$5.99
  • 1 year₹1,699$45

One payment; a pass never renews. The price shown is the total you pay: no fees or charges are added at checkout.

It also opens every other in-depth part in Learn and every Pro tool. Sales are final, except where the law gives you a right to withdraw, for example in the EU and the UK (refund policy).

Interview questions

  1. Fresher to mid

    A Java leaderboard keeps scores in a HashMap<String, Integer> and declares a tie when map.get(a) == map.get(b). Every test with scores below 100 passes, but in production two players with 450 points each are not tied. Explain why, and fix it.

    Model answer, Pro. Model answers open with any pass; prices are in the notice on this page. First step and follow-ups

  2. Mid to senior

    A C++ service keeps its settings in an unordered_map<string, string> and only reads it after start-up, yet its memory grows by tens of megabytes a day and the map's size() keeps rising. What is the likely cause, how do you prove it, and how do you prevent it for good?

    Model answer, Pro. First step and follow-ups

  3. Fresher to mid

    You need a map keyed by a city and a day number in Python, Java and Go, and a colleague suggests the string city + day as the key. How would you build the key in each language so that hashing and equality are right, and what can go wrong with the string?

    Model answer, Pro. First step and follow-ups

Key takeaways

  • All five libraries give O(1) average insert, find and delete, but they differ on missing keys, iteration order, key requirements and equality.
  • A missing key raises in Python, returns null in Java, inserts in C++ with [], returns the zero value in Go and undefined from a JavaScript Map.
  • Only Python’s dict and JavaScript’s Map promise insertion order; sort the keys whenever output order matters.
  • Keys must not change while stored; build composite keys from their parts, not by gluing strings.

References

Related tools

Report a problem with this lesson

Quick answers and tool search

Type to search tools or to get a quick answer, for example 18% of 2500. Use the up and down arrow keys to move through the results, Enter to choose, and Escape to close.