🦀 Functional Rust

352: BTreeSet — Sorted Unique Values

Difficulty: 2 Level: Intermediate A sorted set of unique values with O(log n) operations and built-in set algebra.

The Problem This Solves

You have a collection where duplicates should be silently ignored and you need to iterate in sorted order or find all values in a range. A `Vec` requires manual deduplication and a sort call before every output. A `HashSet` deduplicates automatically but gives you no ordering — iteration order is arbitrary. `BTreeSet` is the answer when you need both deduplication and sorted order. Inserting a value that already exists is a no-op. Iteration is always ascending. Range queries work with `.range()` just like `BTreeMap`. Set algebra — union, intersection, difference, symmetric difference — is built in as iterator adapters. The second use case is sorted membership testing. When you need to ask "is this value between the 10th and 90th percentile?", `BTreeSet` lets you walk the ordered structure directly rather than sorting a `Vec` on every query.

The Intuition

Python's `set` is unordered. If you wanted a sorted set, you'd use `sorted(my_set)` when iterating — but that's O(n log n) every time. `BTreeSet` is always sorted, so ordered operations are free after insertion. Think of it as a `BTreeMap<T, ()>` — a B-tree where values are just the keys themselves. The tradeoff is identical: O(log n) per op instead of HashSet's O(1) average, in exchange for permanent sorted order.

How It Works in Rust

use std::collections::BTreeSet;

let mut set: BTreeSet<i32> = BTreeSet::new();
set.insert(30);
set.insert(10);
set.insert(20);
set.insert(10); // duplicate — ignored silently

// Iteration always ascending: 10, 20, 30
for v in &set {
 println!("{v}");
}

// Range query: values between 10 and 25 inclusive
for v in set.range(10..=25) {
 println!("in range: {v}");
}

// Set algebra — built-in iterator adapters
let a: BTreeSet<i32> = [1, 2, 3, 4].into_iter().collect();
let b: BTreeSet<i32> = [3, 4, 5, 6].into_iter().collect();

let union:        Vec<_> = a.union(&b).collect();        // [1,2,3,4,5,6]
let intersection: Vec<_> = a.intersection(&b).collect(); // [3,4]
let difference:   Vec<_> = a.difference(&b).collect();   // [1,2]

// Membership test
println!("{}", set.contains(&20)); // true

What This Unlocks

Key Differences

ConceptOCamlRust
Sorted set`Set` module (balanced BST)`BTreeSet<T>`
Unordered set`Hashtbl` (manual)`HashSet<T>`
Set union`Set.union``.union(&other)` (iterator)
Set intersection`Set.inter``.intersection(&other)`
Set difference`Set.diff``.difference(&other)`
Range query`Set.find_first` + manual`.range(lo..=hi)`
Duplicate insertcompile-time impossiblesilent no-op
use std::collections::BTreeSet;

fn main() {
    let a: BTreeSet<i32> = [1,3,5,7,9].iter().copied().collect();
    let b: BTreeSet<i32> = [3,5,6,7,8].iter().copied().collect();

    let inter: BTreeSet<_> = a.intersection(&b).copied().collect();
    let union: BTreeSet<_> = a.union(&b).copied().collect();
    let diff: BTreeSet<_> = a.difference(&b).copied().collect();
    let sym_diff: BTreeSet<_> = a.symmetric_difference(&b).copied().collect();

    println!("A: {a:?}");
    println!("B: {b:?}");
    println!("A ∩ B: {inter:?}");
    println!("A ∪ B: {union:?}");
    println!("A \ B: {diff:?}");
    println!("A △ B: {sym_diff:?}");
    println!("Range [3,7]: {:?}", a.range(3..=7).collect::<Vec<_>>());
}

#[cfg(test)]
mod tests {
    use super::*;
    #[test] fn intersection() {
        let a: BTreeSet<i32>=[1,2,3].into(); let b: BTreeSet<i32>=[2,3,4].into();
        let r: BTreeSet<_>=a.intersection(&b).copied().collect();
        assert_eq!(r, [2,3].into());
    }
    #[test] fn sorted() {
        let s: BTreeSet<i32>=[5,1,3,2,4].into();
        assert_eq!(s.iter().copied().collect::<Vec<_>>(), vec![1,2,3,4,5]);
    }
    #[test] fn dedup() {
        let mut s = BTreeSet::new();
        for i in [1,1,2,2,3] { s.insert(i); }
        assert_eq!(s.len(), 3);
    }
}
(* OCaml: ordered sets via Set module *)
module IS = Set.Make(Int)

let () =
  let a = IS.of_list [1;3;5;7;9] in
  let b = IS.of_list [3;5;6;7;8] in
  IS.iter (Printf.printf "%d ") (IS.inter a b); print_newline ();
  IS.iter (Printf.printf "%d ") (IS.union a b); print_newline ();
  IS.iter (Printf.printf "%d ") (IS.diff a b); print_newline ()