2

I have an iterator that I would like to analyze using a sliding window of size w. I try to move the first w items from the iterator into a data structure and would like iterate through the remaining items. However, when I use numbers.take(w) I lose ownership of the iterator and cannot consume the remaining items:

use std::collections::VecDeque;

pub fn analysis<I>(numbers: I, w: usize)
where
    I: Iterator<Item = u64>,
{
    let mut window = VecDeque::with_capacity(w);
    for number in numbers.take(w) {
        window.push_back(number);
    }

    for (i, number) in numbers.enumerate() {
        // do some analysis
    }
}
error[E0382]: use of moved value: `numbers`
  --> src/main.rs:12:24
   |
8  |     for number in numbers.take(w) {
   |                   ------- value moved here
...
12 |     for (i, number) in numbers.enumerate() {
   |                        ^^^^^^^ value used here after move
   |
   = note: move occurs because `numbers` has type `I`, which does not implement the `Copy` trait

I found a workaround using the tee function from the itertools crate:

extern crate itertools;

use itertools::Itertools;
use std::collections::VecDeque;

pub fn analysis<I>(numbers: I, w: usize)
where
    I: Iterator<Item = u64>,
{
    let mut window = VecDeque::with_capacity(w);
    let (first_numbers, numbers) = numbers.tee();

    for number in first_numbers.take(w) {
        window.push_back(number);
    }

    for number in numbers.skip(w) {
        window.pop_front();
        window.push_back(number);
        // do stuff
    }
}

However, this strikes me as a little unwieldy. Is there a way to solve this without cloning or duplicating the iterator? In other words: is there a way to split an iterator into two segments that can be used independently?

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
m00am
  • 5,910
  • 11
  • 53
  • 69
  • The duplicate applied to your question: `pub fn analysis(mut numbers: I, w: usize)` / `numbers.by_ref().take(w)`. – Shepmaster Jun 18 '18 at 16:32
  • Even better, you can write it as `let window: VecDeque<_> = numbers.by_ref().take(w).collect();` – Shepmaster Jun 18 '18 at 16:33
  • @Shepmaster, a rust noob here. Any chance you know where in the docs I can find an explanation of why the bound `I: Iterator` works here, even though numbers.tee() is called and `tee()` is not part of the Iterator trait? I expected the bound to be `I: Itertools` in order to use the `tee()` method. That works, but it is not required. Is that just how "supertraits" work? (I don't expect an answer here, but a link to docs or related questions would be great.) – Warren Weckesser Jun 18 '18 at 19:37
  • @WarrenWeckesser [`Itertools` is implemented for any type that is an `Iterator`](https://docs.rs/itertools/0.7.8/itertools/trait.Itertools.html#implementors). See also [How can I add new methods to Iterator?](https://stackoverflow.com/q/30540766/155423) – Shepmaster Jun 18 '18 at 19:52
  • 1
    @Shepmaster Thanks. Looks like I have some experimenting to do. – Warren Weckesser Jun 18 '18 at 20:07
  • 1
    @Shepmaster I tried that before posting, but apparently overlooked the `mut` and misread the error I got. Now it works -.- Thank you for your help. – m00am Jun 19 '18 at 09:34

0 Answers0