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?