Inclusive take_while and split

I have a use case where I want to take elements from an iterator until a certain condition.
The take_while function seemed to be made for that, however it removes an element!
While looking for a better solution, I noticed that with a slice, the split function would have the same "problem". (It's only a problem in my use case)

In this simple example, i want to split the iterator or slice into [1,2,3] and [4,5]:

let v = [1,2,3,4,5];
    
//take_while
let mut it = v.iter();
it.by_ref().take_while(|&&a|a<3); // 1, 2
it; // 4, 5
    
//split
v.split(|&a|a==3); //[1,2], [4,5]

But the 3 is removed.
How should I do this instead? Is there some function I'm missing?
I know I can just use a while loop and some mutable state, but I would like a clean solution.

The itertools crate has two methods peeking_take_while and taking_while_ref for this, depending on how you want the element to be restored:

use itertools::Itertools;

fn main() {
    let mut it = [1, 2, 3, 4, 5].iter();
    println!("{}", it.peeking_take_while(|&x| *x < 3).format(", "));
    println!("{}", it.take_while_ref(|&x| *x < 5).format(", "));
    println!("{}", it.format(", "));
}

(playground)

Output:

1, 2
3, 4
5
2 Likes

There is a nightly method split_inclusive that does what you want.

Alternatively, you can manually iterate using the methods available on stable:

fn main() {
    let mut slice: &[_] = &[1, 2, 3, 4, 5];

    while let Some(index) = slice.iter().position(|x| *x % 2 == 0) {
        let (piece, rest) = slice.split_at(index + 1);
        println!("{:?}", piece);
        slice = rest;
    }

    println!("Remaining: {:?}", slice);
}

(playground)

Output:

[1, 2]
[3, 4]
Remaining: [5]
2 Likes

Thank you very much!
Including itertools and nightly, there are so many of these iterator functions!
It is so easy to overlook the ones you need, at least for me :wink:

1 Like