How do I cycle through an iterator a finite number of times?
I would expect the output of something like this to be 1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3
and then stop:
vec![1, 2, 3].iter().cycle(4)
// ^ but .cycle() doesn't take an argument...
I don't know the length of the iterator to begin with.
The iter method produces an iterator over immutable references. If we want to create an iterator that takes ownership of v1 and returns owned values, we can call into_iter instead of iter . Similarly, if we want to iterate over mutable references, we can call iter_mut instead of iter .
fn last(self) -> Option<Self::Item> Consumes the iterator, returning the last element. This method will evaluate the iterator until it returns None . While doing so, it keeps track of the current element. After None is returned, last() will then return the last element it saw.
The code only looks slow when un-commenting the for loop because it does not do anything otherwise. Iterators are lazy, and only perform some activity when consumed. A for loop is an example of a construct which consumes the iterator.
Starting in the 2021 edition, array. into_iter() uses IntoIterator normally to iterate by value, and iter() should be used to iterate by reference like previous editions.
There is no such an iterator in the std lib.
If you know the iterator size, you can take
your number times the size of the iterator:
fn cycle_n_times<T: Clone>(slice: &[T], count: usize) -> impl Iterator<Item = &T> {
slice.iter().cycle().take(slice.len() * count)
}
Or you can write your own that is more general:
pub struct Ncycles<I> {
orig: I,
iter: I,
count: usize,
}
impl<I: Clone> Ncycles<I> {
fn new(iter: I, count: usize) -> Ncycles<I> {
Ncycles {
orig: iter.clone(),
iter,
count,
}
}
}
impl<I> Iterator for Ncycles<I>
where
I: Clone + Iterator,
{
type Item = <I as Iterator>::Item;
#[inline]
fn next(&mut self) -> Option<<I as Iterator>::Item> {
match self.iter.next() {
None if self.count == 0 => None,
None => {
self.iter = self.orig.clone();
self.count -= 1;
self.iter.next()
}
y => y,
}
}
}
#[test]
fn it_work() {
Ncycles::new(vec![1, 2, 3].iter(), 4).eq(&[1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3]);
}
One simple way is to repeat the iterator itself, take the first 4 and flatten:
fn main() {
let v = vec![1, 2, 3];
let res = std::iter::repeat(v.iter())
.take(4)
.flatten()
.collect::<Vec<_>>();
dbg!(res);
}
Some micro-benchmark result using code in this gist comparing 3 different approaches:
cycle_n
implementation mimicking Iterator::cycle
.Kudos to rustc
, cycle_n
consistently outperforms the other two when the input is reasonably large whereas repeat-take-flatten performs the best for small input.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With