Search code examples
rustintersection

Updating the original HashSet by intersecting with other HashSet, instead of creating a new HashSet


The Rust's HashSet::intersection function creates a new HashSet. How can I update original HashSet by the result of intersection of two HashSets?

fn main() {
    // intersecting two HashSets, creating a new HashSet: OK
    use std::collections::HashSet;
    let a = HashSet::from(["first", "second", "third"]);
    let b = HashSet::from(["first", "third", "fifth", "ninth"]);
    let intersection: HashSet<_> = a.intersection(&b).collect();
    println!("{:?}", intersection);

    
    // intersecting two HashSets, updating the original HashSet: Failed
    let mut a = HashSet::from(["first", "second", "third"]);
    let b = HashSet::from(["first", "third", "fifth", "ninth"]);
    println!("{:?}", a.intersection(&b).collect::<HashSet<_>>());
    println!("{:?}", a);
    a = a.intersection(&b).collect::<HashSet<_>>();  // doesn't work

    // filter: verbose
    let mut a = HashSet::from(["first", "second", "third"]);
    let b = HashSet::from(["first", "third", "fifth", "ninth"]);
    a = a.iter().filter(|&s| b.contains(s)).map(|s| *s).collect::<HashSet<_>>();
    println!("{:?}", a);
}

Solution

  • To do this without allocating a new HashSet, you can use HashSet::retain and only retain the elements that exist in the second HashSet:

    fn main() {
        use std::collections::HashSet;
        let mut a = HashSet::from(["first", "second", "third"]);
        let b = HashSet::from(["first", "third", "fifth", "ninth"]);
        println!("{:?}", a.intersection(&b).collect::<HashSet<_>>());
        a.retain(|x| b.contains(x));
        println!("{:?}", a);
    }
    

    Output:

    {"third", "first"}
    {"first", "third"}
    

    Playground