Rust provides powerful built-in collections like HashSet and BTreeMap for managing unique items and sorted key-value pairs. These types are part of the std::collections module and are commonly used in real-world Rust applications where performance, uniqueness, and order matter.
After learning the basic collections like Vec and HashMap, I wanted to explore more specialized tools. That is when I discovered HashSet and BTreeMap. These collections solve different problems: HashSet is perfect when you need uniqueness, and BTreeMap is ideal when you need keys in sorted order. Understanding when and how to use them gave me more confidence in choosing the right data structure for each job.
In this post, you will learn what these collections are, how to use them, and when to prefer one over the other.
What Is a HashSet?
A HashSet is a collection of unique values. It is like a Vec, but it automatically rejects duplicates.
It is useful when:
- You want to check if a value exists quickly
- You want to collect unique items from a list
- You do not care about order
You need to import it from the standard collections module:
use std::collections::HashSet;
Creating and Using a HashSet
Here is a basic example:
let mut colors = HashSet::new();
colors.insert("red");
colors.insert("blue");
colors.insert("red"); // duplicate, will be ignored
println!("{:?}", colors); // {"blue", "red"}
To check for a value:
if colors.contains("red") {
println!("It is in the set.");
}
To remove an item:
colors.remove("red");
Useful Methods for HashSet
- len(): count of items
- is_empty(): check if it is empty
- clear(): remove all items
- iter(): loop through all items
- retain(): keep items that match a condition
HashSet does not preserve insertion order. If you need order, consider a BTreeSet.
Set Operations
HashSet supports common set operations:
let a: HashSet<_> = [1, 2, 3].into_iter().collect();
let b: HashSet<_> = [3, 4, 5].into_iter().collect();
let union: HashSet<_> = a.union(&b).copied().collect(); // {1, 2, 3, 4, 5}
let intersect: HashSet<_> = a.intersection(&b).copied().collect(); // {3}
let diff: HashSet<_> = a.difference(&b).copied().collect(); // {1, 2}
These are great for comparing user permissions, tags, and categories.
What Is a BTreeMap?
A BTreeMap is a sorted key-value map, like HashMap, but it stores keys in order.
It is useful when:
- You want to iterate keys in sorted order
- You want predictable iteration
- You do not need the speed of a hash map
Import it from the standard library:
use std::collections::BTreeMap;
Creating and Using a BTreeMap
Example:
let mut scores = BTreeMap::new();
scores.insert("Alice", 50);
scores.insert("Bob", 60);
scores.insert("Charlie", 40);
for (name, score) in &scores {
println!("{}: {}", name, score);
}
Output:
Alice: 50
Bob: 60
Charlie: 40
The keys are printed in sorted order automatically.
Access and Modify
- get(key) – returns an Option with the value
- insert(key, value) – inserts or updates a key
- remove(key) – removes a key
if let Some(score) = scores.get("Alice") {
println!("Alice scored {}", score);
}
Comparing HashMap vs BTreeMap
Feature | HashMap | BTreeMap |
---|---|---|
Key Order | No | Yes (sorted by key) |
Performance | Fastest for random access | Slower but predictable |
Memory Usage | Higher | More efficient |
Key Requirements | Needs Hash + Eq traits | Needs Ord + Eq traits |
Use HashMap for performance. Use BTreeMap when you need order.
Example: Counting Unique Words
Here is a practical use of HashSet:
let sentence = "the quick brown fox jumps over the lazy dog";
let words: HashSet<_> = sentence.split_whitespace().collect();
println!("Unique words: {}", words.len()); // 8
Here is an example with BTreeMap:
let sentence = "hello world hello rust";
let mut counts = BTreeMap::new();
for word in sentence.split_whitespace() {
*counts.entry(word).or_insert(0) += 1;
}
for (word, count) in &counts {
println!("{}: {}", word, count);
}
This prints the words in sorted order with their counts.
Summary
Rust’s HashSet and BTreeMap give you powerful tools for working with unique data and sorted key-value pairs. Use HashSet when you want fast, unordered lookups. Use BTreeMap when you want predictable order with sorted keys. These collections are easy to use, memory-efficient, and part of Rust’s safe and expressive ecosystem.