S3.0 What This Teaches
HashMap<K, V> stores key-value pairs with O(1) average lookup.
This tutorial covers:
- Constructing a
HashMapand inserting entries - Looking up values with
get - The entry API for conditional insertion and in-place mutation
- Iterating over keys, values, and pairs
- A practical word-frequency example
S3.1 Construction and Insertion
HashMap is in std::collections, so bring it into scope
with use:
use std::collections::HashMap;
let mut scores: HashMap<String, u32> = HashMap::new();
scores.insert(String::from("Alice"), 90);
scores.insert(String::from("Bob"), 75);
insert returns Option<V> - Some(old_value)
if the key already existed, None if it was new. A second
insert with the same key overwrites the value.
S3.2 get and contains_key
get returns Option<&V> - a reference to the value,
or None if the key is absent:
if let Some(s) = scores.get("Alice") {
println!("Alice: {s}");
}
println!("{:?}", scores.get("Dave")); // None
println!("{}", scores.contains_key("Bob")); // true
scores["Alice"] for direct access when you are certain the key
exists - it panics if it does not.
S3.3 remove
scores.remove("Bob");
remove returns Option<V> - the removed value, or
None if the key was absent.
S3.4 The Entry API
scores.entry(String::from("Dave")).or_insert(70); // adds Dave: 70
scores.entry(String::from("Alice")).or_insert(0); // Alice exists; unchanged
or_insert returns a mutable reference to the value (existing or newly
inserted). Use it directly to modify the value in place:
let alice = scores.entry(String::from("Alice")).or_insert(0);
*alice += 5;
let text = "the quick brown fox jumps over the lazy dog the fox";
let mut freq: HashMap<&str, u32> = HashMap::new();
for word in text.split_whitespace() {
*freq.entry(word).or_insert(0) += 1;
}
S3.5 Iteration
HashMap does not guarantee order. Sort before printing when you need
stable output:
let mut pairs: Vec<(&String, &u32)> = scores.iter().collect();
pairs.sort_by_key(|(k, _)| k.as_str());
for (name, score) in pairs {
println!("{name}: {score}");
}
.keys(), .values(),
.into_iter() (consumes the map and yields owned key-value pairs).
S3.6 Example - All Together
// HashMap - demonstrates construction, lookup, the entry API, and iteration.
use std::collections::HashMap;
fn main() {
// --- construction ---
println!("--- construction ---");
let mut scores: HashMap<String, u32> = HashMap::new();
scores.insert(String::from("Alice"), 90);
scores.insert(String::from("Bob"), 75);
scores.insert(String::from("Carol"), 88);
println!("{scores:?}");
// --- get: returns Option<&V> ---
println!("--- get ---");
if let Some(s) = scores.get("Alice") {
println!("Alice: {s}");
}
println!("Dave: {:?}", scores.get("Dave"));
// --- contains_key ---
println!("--- contains_key ---");
println!("has Bob: {}", scores.contains_key("Bob"));
// --- remove ---
println!("--- remove ---");
scores.remove("Bob");
println!("after remove Bob: {} entries", scores.len());
// --- entry: insert only if absent ---
println!("--- entry or_insert ---");
scores.entry(String::from("Dave")).or_insert(70);
scores.entry(String::from("Alice")).or_insert(0); // Alice exists; unchanged
println!("Dave: {}, Alice: {}", scores["Dave"], scores["Alice"]);
// --- entry: mutate existing value ---
println!("--- entry modify ---");
let alice = scores.entry(String::from("Alice")).or_insert(0);
*alice += 5;
println!("Alice after +5: {}", scores["Alice"]);
// --- sorted iteration ---
println!("--- iteration ---");
let mut pairs: Vec<(&String, &u32)> = scores.iter().collect();
pairs.sort_by_key(|(k, _)| k.as_str());
for (name, score) in pairs {
println!("{name}: {score}");
}
// --- word frequency (classic entry pattern) ---
println!("--- word count ---");
let text = "the quick brown fox jumps over the lazy dog the fox";
let mut freq: HashMap<&str, u32> = HashMap::new();
for word in text.split_whitespace() {
*freq.entry(word).or_insert(0) += 1;
}
let mut fv: Vec<(&&str, &u32)> = freq.iter().collect();
fv.sort_by_key(|(w, _)| **w);
for (word, count) in fv {
println!(" {word}: {count}");
}
}
--- construction ---
{"Bob": 75, "Carol": 88, "Alice": 90}
--- get ---
Alice: 90
Dave: None
--- contains_key ---
has Bob: true
--- remove ---
after remove Bob: 2 entries
--- entry or_insert ---
Dave: 70, Alice: 90
--- entry modify ---
Alice after +5: 95
--- iteration ---
Alice: 95
Carol: 88
Dave: 70
--- word count ---
brown: 1
dog: 1
fox: 2
jumps: 1
lazy: 1
over: 1
quick: 1
the: 3
S3.7 Exercise
Exercise
- Build a
HashMap<&str, Vec<i32>>that groups numbers by a label. Insert"odd" -> [1,3,5]and"even" -> [2,4,6]. Print both groups. - Write a function
char_frequency(s: &str) -> HashMap<char, usize>that counts how often each character appears. Test it on"mississippi"and print results in alphabetical order. - Given two
HashMap<String, u32>maps, write a function that merges the second into the first, summing values for keys that appear in both.
S3.8 Common Mistakes
Indexing with a key that may not exist
println!("{}", scores["Dave"]); // panics if Dave is absent
scores.get("Dave") and handle the Option.Unnecessary allocation on lookup
scores.insert(String::from("Alice"), 90);
scores.get(&"Alice".to_string()); // allocates needlessly
scores.get("Alice"); // works - &str coerces correctly
HashMap accepts any type that implements Borrow<K>
for lookup. &str works directly for String keys -
no .to_string() needed.
Assuming iteration order
for (k, v) in &scores {
println!("{k}: {v}"); // order is non-deterministic across runs
}
HashMap uses a random hash seed. Collect into a Vec and
sort before printing when consistent output is required.
S3.9 Key Terms
| Term | Meaning |
|---|---|
| HashMap<K, V> | Hash table mapping keys of type K to values of type V |
| insert | Adds or overwrites a key-value pair; returns the old value as Option<V> |
| get | Returns Option<&V> for a given key; does not panic |
| remove | Removes a key and returns its value as Option<V> |
| entry API | entry(key).or_insert(val) - insert-if-absent with one lookup |
| or_insert | Returns &mut V to the existing or newly inserted value |
| contains_key | Returns bool indicating whether the key is present |
| Borrow | Trait that lets String keys be looked up via &str references |