I want perform the following, in pseudocode:
(a, b, c) = (HashSet(...), HashSet(...), HashSet(...))
(a, b, c) = (a - b - c, b - a - c, c - a - b)
In Rust I tried something like this:
fn get_random_set(...) -> HashSet<String> {
...
}
// Sets of randomly generated "words" that define behavior of the whole program.
let action_plus: HashSet<String> = get_random_set();
let action_minus: HashSet<String> = get_random_set();
let action_new_line: HashSet<String> = get_random_set();
Now we are to exclude all the common "words" from these HashSet
s.
I learned that difference
and union
methods return Difference
and Union
iterators. And if I do this:
let action_plus = HashSet::from(action_minus.union(&action_new_line).collect::<Vec<String>>());
I receive this:
the trait `From<Vec<String>>` is not implemented for `HashSet<_, _>`
How to deal with this problem?
Your goal is to remove any element that's in more than one set from all the sets. Since you are only removing elements, you don't need to clone any strings, and you can perform all operations in place. If your sets are called a
, b
and c
, you can use this code:
a.retain(|x| b.remove(x) | c.remove(x));
b.retain(|x| c.remove(x));
This will first remove any element in the intersections between a
and b
as well as a
and c
, respectively, from both sets, and then all elements in the intersection between b
and c
. Overall, this should be much faster than the approaches discussed in the other answers (though I didn't do any benchmarks).
Note that it's important that the first line uses the non-shortcircuiting |
operator rather than ||
. The last operand, c.remove(x)
, obviously has a side effect, so we can't skip it. Otherwise, elements that are in all three sets would not be removed from c
.