Description
Proposal
Problem statement
The existing take_while
method on Iterator
is useful for getting elements that satisfy a predicate. However, it has the notable drawback of removing the first element that doesn't satisfy the predicate, since it must take that element from the iterator to determine if the predicate is finished.
This proposal adds a method take_while_inclusive
that returns elements that satisfy a predicate, but also including that first element that didn't satisfy said predicate. The rest of the iterator is left unchanged and thus no elements are lost.
Motivation, use-cases
Here's the use case in which I wanted this method (paraphrasing since it's closed source). I was parsing a list of parameters that can contain in itself a list of values, so I needed to conditionally take more values from an iterator to create that element.
In this case, since the first element not satisfying the predicate represents a delimiter, it should be included with the other elements. In other cases, you might need to split that last element off to add it back into the collection.
const LIST_START: &str = "[";
const LIST_END: &str = "]";
let s = "a,b,c,[d,e,f],g";
let mut items = s.split(',');
let mut collected = Vec::new();
while let Some(item) = items.next() {
if item.starts_with(LIST_START) {
// item is the start of a list, so collect all the remaining nested list elements together
let list = std::iter::once(item)
.chain((&mut items).take_while_inclusive(|s| !s.ends_with(LIST_END)))
.collect();
collected.push(list);
} else {
collected.push(item.to_string());
}
}
assert_eq!(collected, ["a", "b", "c", "[def]", "g"].map(ToString::to_string));
Also see the first Rust issue in which this was discussed for an example of a use case involving histogram bins: rust-lang/rust#62208
Solution sketches
In the absence of this method, I initially used the take_while_ref
method from itertools
. However, this clones the first element that doesn't satisfy the predicate, which is less than ideal in my use case and impossible in others. My current code uses peeking_take_while
and manually adds that next element back.
Links and related work
My PR to itertools
implementing said method: rust-itertools/itertools#616
First discussed addition to std in rust-lang/rust#62208
Issue for addition to itertools
: rust-itertools/itertools#597
The PR to itertools has been put on hold before investigating if this is an appropriate addition to std
(to prevent another instance of collision like intersperse
).