Add `partition_into` as a function on Iterator

I think that the following function would be a good addition to the iterator trait:

/// Consumes the iterator pumping all the elements that satisfy 
/// `predicate` into `left` and those that don't into `right`.
///
/// `split_into()` takes a closure that returns `true` or `false`. It 
/// applies this closure to a reference to each element of the iterator. 
/// If it returns `true` then it calls the `left` consuming closure with
/// that element. If it returns `false` then it calls the `right` closure.
///
/// `split_into()` consumes the whole iterator (until the first `None`)
///
/// # Examples
///
/// Basic usage:
///
/// ```
/// let a = [1, 2, -3];
/// let t = vec![];
/// let h = Hashset::new();
///
/// a.into_iter().split_into(|&x| x > 0, |x| t.push_back(x), |x| h.insert(x));
/// assert!(t.len() == 2);
/// assert!(h.len() == 1);
/// ```
///
fn split_into<L, R, P>(&mut self, predicate: P, left: L, right: R) where
    L: FnMut(Self::Item),
    R: FnMut(Self::Item),
    P: FnMut(&Self::Item) -> bool;

I’m wondering: it this so much better than

a.into_iter().for_each(|x| if *x > 0 {t.push_back(x)} else {h.insert(x)});

?

(Edit: IMHO it’s worse.)

4 Likes

So this would just be:

self.for_each(|x| if predicate(&x) { left(x) } else { right(x) })

Does that really need to be in Iterator? For the user, it also has a disadvantage compared to writing your own for_each, because you would be forced to have distinct mutable borrows in your three separate closures, whereas a for_each can blend borrows across each part.

8 Likes