Rust HashSet
A HashSet stores unique values with no repeats. Imagine a guest list at the door of an event: a name appears once, and the host checks it in a moment. Sets answer the question "is this item present?" extremely fast, and they remove duplicates without extra effort.
Creating a HashSet
The type lives in the standard collections module. Bring it into scope with a use line.
use std::collections::HashSet;
fn main() {
let mut colors: HashSet<&str> = HashSet::new();
colors.insert("red");
colors.insert("green");
colors.insert("red"); // duplicate, ignored
println!("{}", colors.len());
}
2
insert "red" --> { red }
insert "green" --> { red, green }
insert "red" --> { red, green } (no change)
The Return Value of insert
The insert method returns a bool. A true value means the item was new, and false means the set already held it.
let mut seen = HashSet::new();
println!("{}", seen.insert(10)); // true
println!("{}", seen.insert(10)); // falseBuilding from a Vector
A set removes duplicates from a list in one step.
let numbers = vec![3, 1, 3, 2, 1, 5];
let unique: HashSet<i32> = numbers.into_iter().collect();
println!("{}", unique.len()); // 4Shortcut for small sets: HashSet::from([1, 2, 3]).
Checking and Removing
let mut fruits = HashSet::from(["apple", "mango", "pear"]);
println!("{}", fruits.contains("mango")); // true
fruits.remove("mango");
println!("{}", fruits.contains("mango")); // falseLooping Through a Set
A set has no fixed order. The loop may print items in a different sequence on each run. Sort the items first when order matters.
let mut items: Vec<_> = fruits.iter().collect();
items.sort();
for item in items {
println!("{item}");
}Set Math
Sets support the same operations taught in school math. Two class rosters show the idea.
let math: HashSet<&str> = HashSet::from(["Anu", "Ben", "Cara"]);
let art: HashSet<&str> = HashSet::from(["Ben", "Dev", "Cara"]);
math art +---------+ +---------+ | Anu | | Dev | | +----+-----+---+ | | | Ben, Cara | | | +----+-----+---+ | +---------+ +---------+
Intersection
The intersection holds items present in both sets.
let both: Vec<_> = math.intersection(&art).collect();
// Ben, Cara (any order)Union
The union holds every item from either set, without repeats.
let all: HashSet<_> = math.union(&art).collect();
println!("{}", all.len()); // 4Difference
The difference holds items in the first set that the second set lacks.
let only_math: Vec<_> = math.difference(&art).collect();
// AnuSymmetric Difference
The symmetric difference keeps items that appear in exactly one set. Here the result holds Anu and Dev.
Which Types Fit in a Set
Stored items need the Eq and Hash traits. Integers, strings, booleans, and characters qualify. Floating-point numbers do not qualify, because NaN breaks equality rules. Custom structs qualify after adding a derive line.
#[derive(Debug, Hash, PartialEq, Eq)]
struct Tag {
name: String,
}A Practical Example: Finding Duplicates
fn first_duplicate(values: &[i32]) -> Option<i32> {
let mut seen = HashSet::new();
for &v in values {
if !seen.insert(v) {
return Some(v);
}
}
None
}
fn main() {
println!("{:?}", first_duplicate(&[4, 8, 15, 8, 16]));
}
Some(8)
BTreeSet for Sorted Output
The BTreeSet type keeps items in sorted order automatically. It runs slightly slower than HashSet, yet the loop output stays predictable.
use std::collections::BTreeSet;
let sorted: BTreeSet<i32> = [5, 1, 4, 1, 3].into_iter().collect();
println!("{:?}", sorted); // {1, 3, 4, 5}Common Mistakes
Expecting a fixed print order leads to confusing test failures. The internal layout changes between runs, so sort the items or choose BTreeSet when order matters.
Storing floating-point numbers fails, because floats do not implement Eq and Hash. Convert values to integers, or wrap them in a type that defines equality clearly.
Forgetting that insert keeps the original item can surprise you. When a new value equals an existing one, the set keeps the old one.
Real-World Uses
- Removing duplicate email addresses from a signup list
- Tracking visited pages while exploring a website
- Checking which tags two articles share
- Finding students enrolled in one course but not another
- Detecting repeated values in a stream of data
Practice Ideas
- Count the unique words in a sentence after converting each word to lowercase.
- Find the common friends of two people stored as sets of names.
- Check whether two lists hold the same items regardless of order.
Performance Notes
Insertion, lookup, and removal take roughly constant time on average, even for sets with millions of items. A vector needs a full scan for the same lookup. Choose a set whenever your code repeatedly asks whether an item exists.
Key Points
- A HashSet stores each value once and checks membership quickly.
insertreports whether the item was new.- Union, intersection, and difference compare two sets.
- Iteration order is not guaranteed; use
BTreeSetfor sorted order.
