Hash Maps and Hash Sets

remove() and retain()

HashMap<K, V> provides .remove(&q) and .remove_entry(&q) to delete a single entry by key in $O(1)$ average time, and .retain(predicate) (plus .extract_if() / .clear()) to filter entries across the entire table in $O(\text{capacity})$ time.

Summary of Removal Methods on HashMap<K, V>

Method Signature Return Type Behavior
map.remove(&q) fn remove<Q>(&mut self, k: &Q) -> Option<V> Option<V> Removes (K, V), drops K, and returns Some(V) (or None if absent)
map.remove_entry(&q) fn remove_entry<Q>(&mut self, k: &Q) -> Option<(K, V)> Option<(K, V)> Removes and returns both the owned key K and value V
map.retain(f) fn retain<F>(&mut self, f: F) where F: FnMut(&K, &mut V) -> bool () Visits every entry, allowing mutation of &mut V and keeping only entries where f returns true
map.clear() fn clear(&mut self) () Drops all (K, V) pairs while keeping allocated bucket capacity

Recovering Owned Keys and Values with remove() and remove_entry()

When K is an owned heap type like String and you query with a borrowed &str, map.remove_entry("key") lets you recover ownership of the stored String key without cloning it beforehand:

use std::collections::HashMap;

fn main() {
    let mut sessions = HashMap::from([
        (String::from("sess_101"), "alice"),
        (String::from("sess_102"), "bob"),
    ]);

    // 1. `remove` returns only `Option<V>` and drops the `String` key:
    let user1 = sessions.remove("sess_101");
    println!("Removed value: {user1:?}");

    // 2. `remove_entry` returns `Option<(K, V)>`, recovering the owned `String` key:
    if let Some((owned_key, user2)) = sessions.remove_entry("sess_102") {
        println!("Removed pair:  key='{owned_key}', user='{user2}'");
    }
}
Removed value: Some("alice")
Removed pair:  key='sess_102', user='bob'

In-Place Filtering and Value Mutation with retain()

Because the closure passed to map.retain(|key, val| ...) receives (&K, &mut V), you can update each value and prune expired entries in a single pass:

use std::collections::HashMap;

fn main() {
    let mut ttl_seconds = HashMap::from([
        ("token_a", 30_u32),
        ("token_b", 5),
        ("token_c", 10),
    ]);

    // Elapsed 10 seconds: subtract 10 from each TTL and keep only entries with TTL > 0:
    ttl_seconds.retain(|_token, ttl| {
        *ttl = ttl.saturating_sub(10);
        *ttl > 0
    });

    println!("Active tokens after 10s: {ttl_seconds:?}");
}
Active tokens after 10s: {"token_a": 20}