How can I insert all values of one HashSet into another HashSet?
Asked Answered
C

3

32

I have two HashSet<u16>s and I would like to implement a = a U b. If possible, I'd like to use HashSet::union rather than loops or other tweaks.

I tried the following:

use std::collections::HashSet;
let mut a: HashSet<u16> = [1, 2, 3].iter().cloned().collect();
let b: HashSet<u16> = [7, 8, 9].iter().cloned().collect();  

// I can build a union object that contains &u16
let union: HashSet<&u16> = a.union(&b).collect();

// But I can't store the union into a
a = a.union(&b).collect();   //  -> compile error

// of course I can do
for x in &b {
    a.insert(*x);
}
// but I wonder if union could not be used to simply build a union

The error message is the following:

the trait bound 
`std::collections::HashSet<u16>: std::iter::FromIterator<&u16>`
is not satisfied

How can I perform a = a U b?

Counterpoint answered 15/5, 2019 at 11:45 Comment(0)
S
43

You don't want union — as you said, it will create a new HashSet. Instead you can use Extend::extend:

use std::collections::HashSet;

fn main() {
    let mut a: HashSet<u16> = [1, 2, 3].iter().copied().collect();
    let b: HashSet<u16> = [1, 3, 7, 8, 9].iter().copied().collect();

    a.extend(&b);

    println!("{:?}", a); // {8, 3, 2, 1, 7, 9}
}

(Playground)

Extend::extend is also implemented for other collections, e.g. Vec. The result for Vec will differ because Vec does not honor duplicates in the same way a Set does.

Smallscale answered 15/5, 2019 at 11:54 Comment(1)
Great, exactly what I was looking for. Plus it teaches me that I should not only look at the 'methods' section of the doc to find methods, but also into the traits a struct implements. Rust is really a world on its own :-)Counterpoint
M
2
// But I can't store the union into a
a = a.union(&b).collect();   //  -> compile error

The error message is the following:

the trait bound  `std::collections::HashSet<u16>:
std::iter::FromIterator<&u16>` is not satisfied

It's because a is a HashSet<u16>, but a.union(&b) is an Iterator<Item=&u16>. Converting a.union(&b) to Iterator<Item=u16> by using .copied() works:

a = a.union(&b).copied().collect(); // compiles

As the other mentioned, this will create a new HashSet. In some cases, this might be what you want, but it will make more sense if it's assigned to another variable:

let c: HashSet<u16> = a.union(&b).copied().collect();

// a is unchanged here
Milburr answered 10/5, 2021 at 14:15 Comment(0)
I
0

For collecting multiple hashsets:

use std::collections::HashSet;

fn main() {
    let a: HashSet<u16> = [1, 2, 3].iter().copied().collect();
    let b: HashSet<u16> = [1, 3, 7, 8, 9].iter().copied().collect();
    let all = [a,b];
    let combined = all.iter().flatten().collect::<HashSet<_>>();

    println!("{:?}", combined);
}

Playground: https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=44cd73eb3a4e628378cbb7ff11a32649

Iceblink answered 19/12, 2022 at 19:10 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.