Set operations, results and references

I noticed that the HashSet set operations return operation-specific types; .difference() returns a Difference, etc. The operation result types implement Iterator; the idea presumably being "We don't know what you want to stick the result into -- here's an Iterator so you can stick the result wherever you need it.", which is really neat!

However if you simply .collect() the results you'll get node of references:

let mut s1 = HashSet::new();
s1.insert("hello".to_owned());
let mut s2 = HashSet::new();
s2.insert("hello".to_owned());
s2.insert("world".to_owned());
let isect = s1.intersection(&s2);
let res: HashSet<_> = isect.collect();

// res == s1 ???

At this point s1 and s2 will be HashSet<String>, while res will be HashSet<&String>. I presume this is to avoid unnecessary clones -- but I'm in a situation where I need to create an intersection of two sets, then check if the result is identical to s1. This causes a problem because of the type difference.

I solved this by:

let res: HashSet<_> = isect.map(|x| x.to_string()).collect();

.. but I have a distinct feeling that there's a better way to to it.

Is there a "nice and clean" way to do this without having to allocating the res strings?

Have you considered HashSet::is_subset (i.e. s1.is_subset(&s2))?

Yeah, I should probably have added a note that this isn't a question about the actual set operation. I just stripped down one example to illustrate the problem, but it's not actually merely a subset.

Basically I'm wondering what the simplest way to compare a HashSet<String> against a HashSet<&String> is.

In that case you could probably copy the code used to implement PartialEq for HashSet, something like res.len() == s1.len() && res.iter().all(|&key| s1.contains(key))

1 Like

If you would want allocated copies, a slightly better way to collect them is isect.cloned().collect().