You have a sorted map keyed by time, port number, or version, and you want every entry between two keys. Filtering on iter() walks the whole map — BTreeMap::range walks just the slice you asked for.
The filter-everything pattern
1
2
3
4
5
6
7
8
9
10
11
| use std::collections::BTreeMap;
let mut map = BTreeMap::new();
map.insert(1, "a");
map.insert(3, "c");
map.insert(5, "e");
map.insert(7, "g");
// Walk every entry, skip the ones you don't want.
let hits: Vec<_> = map.iter().filter(|(k, _)| (3..7).contains(*k)).collect();
assert_eq!(hits, vec![(&3, &"c"), (&5, &"e")]);
|
Correct, but with a million entries you still traversed all of them. BTreeMap::range takes a RangeBounds and seeks straight to the start key, iterating only through the requested window:
1
2
3
4
5
6
7
| use std::collections::BTreeMap;
let map: BTreeMap<i32, &str> =
BTreeMap::from([(1, "a"), (3, "c"), (5, "e"), (7, "g")]);
let hits: Vec<_> = map.range(3..7).collect();
assert_eq!(hits, vec![(&3, &"c"), (&5, &"e")]);
|
Same result, log-N lookup to the first key, in-order iteration from there.
All the usual range syntax works
Any RangeBounds<K> is fair game — .., a..b, a..=b, ..b, a..:
1
2
3
4
5
6
7
8
9
10
11
12
13
| use std::collections::BTreeMap;
let map: BTreeMap<i32, &str> =
BTreeMap::from([(1, "a"), (3, "c"), (5, "e"), (7, "g")]);
let inclusive: Vec<_> = map.range(3..=7).collect();
assert_eq!(inclusive, vec![(&3, &"c"), (&5, &"e"), (&7, &"g")]);
let from_five: Vec<_> = map.range(5..).collect();
assert_eq!(from_five, vec![(&5, &"e"), (&7, &"g")]);
let up_to_five: Vec<_> = map.range(..5).collect();
assert_eq!(up_to_five, vec![(&1, &"a"), (&3, &"c")]);
|
For an exclusive start (rare but it happens), reach for Bound::Excluded:
1
2
3
4
5
6
7
8
| use std::collections::BTreeMap;
use std::ops::Bound::{Excluded, Unbounded};
let map: BTreeMap<i32, &str> =
BTreeMap::from([(1, "a"), (3, "c"), (5, "e"), (7, "g")]);
let after_three: Vec<_> = map.range((Excluded(3), Unbounded)).collect();
assert_eq!(after_three, vec![(&5, &"e"), (&7, &"g")]);
|
Mutate in place with range_mut
range_mut gives you &mut V for each entry in the window — keys stay immutable (they have to, the map’s invariant depends on them):
1
2
3
4
5
6
7
8
9
10
11
12
13
| use std::collections::BTreeMap;
let mut scores: BTreeMap<i32, i32> =
BTreeMap::from([(1, 10), (3, 10), (5, 10), (7, 10)]);
for (_, v) in scores.range_mut(3..=5) {
*v += 1;
}
assert_eq!(scores[&1], 10);
assert_eq!(scores[&3], 11);
assert_eq!(scores[&5], 11);
assert_eq!(scores[&7], 10);
|
The same trick works on BTreeSet::range.
Takeaway
When you find yourself filtering a BTreeMap by a range of keys, swap the filter for range. You get O(log n) seek plus O(k) iteration over just the matches, and the code reads more like the intent.