For some iterators I'd like a function like nth() that accepts an ordered sequence of more than one index. This is useful to avoid scanning the same iterable more than once.
A eager and rough version of it:
fn multi_nth<It1, It2>(mut seq: It1, idxs: It2) -> Vec<u64>
where It1: Iterator<Item=u64>, It2: Iterator<Item=usize> {
let mut result = vec![];
let mut si = 0;
'OUTER: for i in idxs {
while si <= i {
if let Some(x) = seq.next() {
if si == i { result.push(x); }
si += 1;
} else {
break 'OUTER;
}
}
}
result
}
Do you know where to find a lazy version of this, and if it's a good idea to add it to std lib or itertools?
I've tried to improve your code a little, now it's usable in an iterator chain. But the handling of indexes is still wrong, and now I'm too much sleepy to debug it (debugging from other people is welcome):
#[derive(Debug)]
struct MultiNthState<I, N>
where I: Iterator
{
indexes: N,
iter_idx: usize,
underlying: I,
}
trait MultiNth: Iterator {
fn multi_nth<N>(self, indexes: N) -> MultiNthState<Self, N>
where N: Iterator<Item=usize>,
Self: Sized,
{
MultiNthState { indexes, iter_idx: 0, underlying: self }
}
}
impl<I> MultiNth for I where I: Iterator {}
impl<I, N> Iterator for MultiNthState<I, N>
where I: Iterator,
N: Iterator<Item=usize>,
{
type Item = I::Item;
#[inline]
fn next(&mut self) -> Option<Self::Item> {
match self.indexes.next() {
None => None,
Some(idx) => {
let mut res = match self.underlying.next() {
None => return None,
Some(next) => next
};
self.iter_idx += 1;
while self.iter_idx < idx {
self.iter_idx += 1;
res = match self.underlying.next() {
None => return None,
Some(next) => next
};
}
Some(res)
}
}
}
}
fn main() {
// Indexes must be ordered and strictly increasing?
for f in [10, 20, 30, 40, 50, 60, 70]
.iter()
.multi_nth([1, 2, 5].iter().cloned()) {
println!("{}", f); // Should print: 20 30 60
}
}
A possible solution is to assume the indexes are few (and they are Copy), you can define an Increasing struct with a smart constructor that gives the error: