# The best way to write set operations

I end up having to write something like

``````        // Calculate the union of three sets that are intersections of three original sets
let i1: BTreeSet<Item> = set1.intersection(&set2).map(|v| *v).collect();
let i2: BTreeSet<Item> = set1.intersection(&set3).map(|v| *v).collect();
let i3: BTreeSet<Item> = set2.intersection(&set3).map(|v| *v).collect();
let u: Vec<Item> = i1
.union(&i2)
.map(|v| *v)
.collect::<BTreeSet<Item>>()
.union(&i3)
.map(|v| *v)
.collect();
``````

I am not happy that I am not able to write

``````    let u = set1.intersection(set2).union(set1.intersection(set3)).union(set2.intersection(set3));
``````

or more step by step,

``````    let i1 = set1.intersection(set2);
let i2 = set1.intersection(set3);
let i3 = set2.intersection(set3);
let u = i1.union(i2).union(i3);
``````

Any idea to write some better workable code for this simple algorithm?

You can, you just need to use operators.

``````let u = &(&(&set1 & &set2) | &(&set1 & &set3)) | &(&set2 & &set3);
``````

Admitted, the fact that every operand needs to be borrowed makes this a bit less readable than one might like.

@steffahn

That helped a lot! I tried the "step by step" way:

``````let i1 = &set1 & &set2;
let i2 = &set1 & &set3;
let i3 = &set2 & &set3;
let u = &(&i1 | &i2) | &i3;
``````

I don't think you need to `collect` in each step.

``````    let i1 = set1.intersection(&set2);
let i2 = set1.intersection(&set3);
let i3 = set2.intersection(&set3);
let u = i1.chain(i2).chain(i3).copied().collect::<BTreeSet<Item>>();
``````

Yes that's another way. But then it does not use the standard `union` method, makes the purpose of the code harder to understand.

Talking about efficiency, this can be done in a single iteration e.g.

``````use itertools::EitherOrBoth::{Both, Left};
use itertools::Itertools;
let u: BTreeSet<Item> = set1
.iter()
.merge_join_by(&set2, Ord::cmp)
.merge_join_by(&set3, |a_b, c| a_b.as_ref().reduce(|a, _b| a).cmp(c))
.filter_map(|a_b_c| match a_b_c {
Both(a_b, _c) => Some(a_b.reduce(|a, _b| a)),
Left(Both(a, _b)) => Some(a),
_ => None,
})
.copied()
.collect();
``````

(disclaimer: code compiles but is completely untested)

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.