🎓 A1Learner
🔍

Rust HashMap

A HashMap is a collection that stores pairs of a key and a value. A lookup uses the key to find its value quickly.

Put a pair in

insert stores a value under a key. The map starts empty — the use line sits at the top of the file, as in the closing example:

let mut prices = HashMap::new();
prices.insert("apple", 3);

Look a value up with get

get answers an Option: Some with the value when the key is there, None when it is not:

prices.insert("apple", 3);
println!("apple = {:?}", prices.get("apple"));
println!("pear = {:?}", prices.get("pear"));

The same key replaces the value

Insert a key twice and the second value wins. The map still holds one pair for that key:

let mut scores = HashMap::new();
scores.insert("Blue", 10);
scores.insert("Blue", 20);
println!("Blue = {} pairs = {}", scores["Blue"], scores.len());

Count things with entry

entry(key).or_insert(0) starts a new key at 0, then hands you the count so you can change it. This one line is the standard counting pattern:

let mut counts: HashMap<&str, u32> = HashMap::new();
for w in ["the", "cat", "the"] {
    *counts.entry(w).or_insert(0) += 1;
}
println!("the = {}", counts["the"]);

A plain value, with a fallback

get hands you a reference inside an Option. copied() makes it a plain value, and unwrap_or(0) covers a missing key:

let mut scores = HashMap::new();
scores.insert("Blue", 10);
let blue = scores.get("Blue").copied().unwrap_or(0);
let red = scores.get("Red").copied().unwrap_or(0);
println!("blue = {blue} red = {red}");

Change a value only if the key is there

and_modify runs your closure on the stored value when the key exists. Chain or_insert after it, and one line covers both cases:

visits.entry(page).and_modify(|v| *v += 1).or_insert(1);

Example

use std::collections::HashMap;
fn main() {
    let text = "the quick the fast the";
    let mut counts: HashMap<&str, u32> = HashMap::new();
    for w in text.split_whitespace() { *counts.entry(w).or_insert(0) += 1; }
    println!("the appears {} times", counts["the"]);
}

Key points

  • A HashMap pairs each key with one value.
  • insert moves owned keys and values into the map.
  • A String inserted into the map belongs to the map afterwards.
  • Copy values like i32 are copied instead.
  • HashMap is not in the prelude and has no vec!-style macro.
  • That is why the use line is always needed.
  • All keys share one type.
  • All values share one type.

In this example, the program counts how often each word appears in a short text. split_whitespace gives the words one by one. For each word, entry(w).or_insert(0) means this. If this word is new, start its count at 0. Then give me the count so I can change it. The * and += 1 add one to that count. "the" appears three times, so counts["the"] prints 3. This entry pattern is the standard Rust way to count things.

Note

A HashMap visits its pairs in no promised order.

Use BTreeMap when sorted order is needed.

Try it Yourself

Edit the code, then press Run.

Running is simulated · Rust Playground

Exercise

What does counts.entry(w).or_insert(0) return?