itertools icon indicating copy to clipboard operation
itertools copied to clipboard

Add more set methods: intersect, difference

Open alecmocatta opened this issue 2 years ago • 0 comments

If you have two sorted iterators (e.g. from BTreeMap::keys) there are various set operations you might want to perform, including union, intersection, difference and symmetric_difference.

union is implemented via itertools::merge.

The others can be implemented with itertools::merge_join_by + filter_map and probably itertools::diff_with. But perhaps there should be more direct implementations?

Here's a direct implementation of intersection, for example:

#[derive(Debug)]
pub struct Intersect<A, B> {
    a: A,
    b: B,
}
impl<A, B> Iterator for Intersect<A, B>
where
    A: Iterator,
    B: Iterator<Item = A::Item>,
    A::Item: Ord,
{
    type Item = A::Item;
    fn next(&mut self) -> Option<Self::Item> {
        let (mut a, mut b) = (self.a.next(), self.b.next());
        loop {
            match (a.is_none(), &a).cmp(&(b.is_none(), &b)) {
                Ordering::Equal => break a,
                Ordering::Less => a = self.a.next(),
                Ordering::Greater => b = self.b.next(),
            }
        }
    }
    #[inline(always)]
    fn size_hint(&self) -> (usize, Option<usize>) {
        let min = match (self.a.size_hint().1, self.b.size_hint().1) {
            (Some(a), Some(b)) => Some(cmp::min(a, b)),
            (Some(a), None) | (None, Some(a)) => Some(a),
            (None, None) => None,
        };
        (0, min)
    }
}

alecmocatta avatar Apr 30 '23 18:04 alecmocatta