Rust More Collections
Vectors and HashMaps will cover most of your needs, but Rust's standard library has a few more collections that make some jobs much easier. They all live in std::collections, and once you know when to use them, programs get shorter and clearer.
| Collection | Best for |
|---|---|
Vec | a list in order, found by position |
HashMap | looking up a value by its key |
HashSet | a group of unique items, with fast "is it in there?" checks |
BTreeMap | like HashMap, but the keys stay sorted |
VecDeque | a queue: add at the back, take from the front |
HashSet: no duplicates
A set holds each value at most once. Adding something that is already there simply does nothing. That makes sets perfect for questions like "which different cities did our customers come from?"
use std::collections::HashSet;
fn main() {
let visits = ["Pune", "Mumbai", "Pune", "Delhi", "Mumbai", "Pune"];
let mut cities = HashSet::new();
for city in visits {
cities.insert(city);
}
println!("{} visits from {} different cities", visits.len(), cities.len());
println!("Anyone from Delhi? {}", cities.contains("Delhi"));
}6 visits from 3 different cities Anyone from Delhi? true
Sets can also be compared. intersection gives the items two sets share, and difference the items only in the first:
use std::collections::HashSet;
fn main() {
let asha: HashSet<&str> = ["chess", "music", "cricket"].into_iter().collect();
let ravi: HashSet<&str> = ["cricket", "cooking", "chess"].into_iter().collect();
let mut both: Vec<_> = asha.intersection(&ravi).collect();
both.sort();
println!("Both enjoy {:?}", both);
}Both enjoy ["chess", "cricket"]
BTreeMap: keys in order
A BTreeMap works just like a HashMap, with insert, get and entry, but when you loop over it, the keys always come out sorted. That is perfect for printing reports:
use std::collections::BTreeMap;
fn main() {
let mut marks = BTreeMap::new();
marks.insert("Zoya", 81);
marks.insert("Arjun", 74);
marks.insert("Meera", 93);
for (name, mark) in &marks {
println!("{:6} {}", name, mark);
}
}Arjun 74 Meera 93 Zoya 81
VecDeque: a fair queue
Think of people waiting at a ticket counter: new people join at the back, and the person at the front is served first. A VecDeque (say "vec deck") does exactly this efficiently, with push_back and pop_front:
use std::collections::VecDeque;
fn main() {
let mut queue = VecDeque::new();
queue.push_back("Kiran");
queue.push_back("Leela");
queue.push_back("Omar");
while let Some(person) = queue.pop_front() {
println!("Now serving {} ({} still waiting)", person, queue.len());
}
}Now serving Kiran (2 still waiting) Now serving Leela (1 still waiting) Now serving Omar (0 still waiting)
while let keeps looping as long as the pattern fits, here as long as pop_front returns Some. When the queue is empty it returns None, and the loop ends by itself.
Practice exercises
- Use a
HashSetto find the different words in a sentence that repeats some words. - Store five countries and their populations in a
BTreeMapand print them in alphabetical order. - Simulate a printer queue with
VecDeque: add four documents, then print them in order.