I am trying to create an iterator of iterators where the outer iterator splits the input sequence and each inner iterator iterates over a split.
The interface should looks something like this:
let vec = vec![1, 2, 3, 10, 11, 12, 50, 120, 121, 122];
let splits = vec.iter().split_by(|&a, &b| a + 1 != b);
for split in splits {
println!("split = {:?}", split.collect::<Vec<_>>());
}
with an output of:
split = [1, 2, 3]
split = [10, 11, 12]
split = [50]
split = [120, 121, 122]
Since I need to remember the previous element of the iteration (to pass the “a
” to the closure) the items need to be Copy
. Alternatively, a key-closure provides a Copy
value for an item, like so:
let vec = vec!["abc", "run", "tag", "go", "be", "ring", "zip"];
let splits = vec.iter().split_by_key(|x| x.len(), |&a, &b| a != b);
for split in splits {
println!("split = {:?}", split.collect::<Vec<_>>());
}
with an output of:
split = ["abc", "run", "tag"]
split = ["go", "be"]
split = ["ring"]
split = ["zip"]
The following shows my current work. I am stuck at how to manage the lifetimes required such that the inner iterator Split
can advance the parent iterator managed by the outer iterator SplitBy
:
struct SplitBy<I, K, C, F>
where
I: Iterator,
K: Fn(&I::Item) -> C,
C: Copy,
F: Fn(C, C) -> bool,
{
iter: Peekable<I>,
make_key: K,
is_split: F,
}
impl<I, K, C, F> Iterator for SplitBy<I, K, C, F>
where
I: Iterator,
K: Fn(&I::Item) -> C,
C: Copy,
F: Fn(C, C) -> bool,
{
type Item = Split<'a, I, K, C, F>;
fn next(&mut self) -> Option<Self::Item> {
if let Some(first) = self.iter.peek() {
Some(Split {
parent: self, // <- this is the part I am most unsure about
prev: (self.make_key)(first),
is_init: true,
})
} else {
None
}
}
}
struct Split<'a, I, K, C, F>
where
I: Iterator,
K: Fn(&I::Item) -> C,
C: Copy,
F: Fn(C, C) -> bool,
{
parent: &'a mut SplitBy<I, K, C, F>,
prev: C,
is_init: bool,
}
impl<'a, I, K, C, F> Iterator for Split<'a, I, K, C, F>
where
I: Iterator,
K: Fn(&I::Item) -> C,
C: Copy,
F: Fn(C, C) -> bool,
{
type Item = I::Item;
fn next(&mut self) -> Option<I::Item> {
if self.is_init {
return self.parent.iter.next();
} else {
if let Some(peek) = self.parent.iter.peek() {
let peek_id = (self.parent.make_key)(peek);
if (self.parent.is_split)(self.prev, peek_id) {
return None;
} else {
return self.parent.iter.next();
}
}
}
None
}
}
The code above is largely inspired by GroupBy
and Group
from the Itertools crate.
The code in Split::next
is wrong, but I am able to fix that once Split
can communicate with SplitBy
. Does someone have a pointer what I am missing?