Hashset

#222 Jun 2026

222. HashSet::intersection / union / difference — Set Math Without the Manual Loops

Need the items two collections have in common, or the ones only in one of them? Don’t write a for loop with .contains() inside. HashSet has set algebra built in.

The hand-rolled intersection is a loop, a temp Vec, and a membership check you have to get right:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
use std::collections::HashSet;

let a: HashSet<i32> = [1, 2, 3, 4].into_iter().collect();
let b: HashSet<i32> = [3, 4, 5, 6].into_iter().collect();

let mut common = Vec::new();
for x in &a {
    if b.contains(x) {
        common.push(*x);
    }
}
common.sort();
assert_eq!(common, vec![3, 4]);

HashSet gives you the four set operations directly. Each returns a lazy iterator that borrows both sets, so nothing is allocated until you collect:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
use std::collections::HashSet;

let a: HashSet<i32> = [1, 2, 3, 4].into_iter().collect();
let b: HashSet<i32> = [3, 4, 5, 6].into_iter().collect();

// In both
let mut common: Vec<i32> = a.intersection(&b).copied().collect();
common.sort();
assert_eq!(common, vec![3, 4]);

// In either
let mut all: Vec<i32> = a.union(&b).copied().collect();
all.sort();
assert_eq!(all, vec![1, 2, 3, 4, 5, 6]);

// In a, not in b
let mut only_a: Vec<i32> = a.difference(&b).copied().collect();
only_a.sort();
assert_eq!(only_a, vec![1, 2]);

// In exactly one
let mut either: Vec<i32> = a.symmetric_difference(&b).copied().collect();
either.sort();
assert_eq!(either, vec![1, 2, 5, 6]);

The iterators yield &T, which is why .copied() shows up before collect — drop it if you’d rather collect references. (The .sort() calls are only there to make the asserts deterministic; set iteration order isn’t fixed.)

Just asking a yes/no question?

If you only need to know the relationship, not materialize it, three predicates answer in one call without building anything:

1
2
3
4
5
6
7
8
9
use std::collections::HashSet;

let a: HashSet<i32> = [1, 2, 3, 4].into_iter().collect();
let small: HashSet<i32> = [3, 4].into_iter().collect();
let far: HashSet<i32> = [9, 10].into_iter().collect();

assert!(small.is_subset(&a));
assert!(a.is_superset(&small));
assert!(a.is_disjoint(&far));

Whenever you catch yourself looping over one collection to test membership in another, reach for these instead — the intent reads straight off the method name.