Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

How can I iterate over a sequence multiple times within a function?

I have a function that I would like to take an argument that can be looped over. However I would like to loop over it twice. I tried using the Iterator trait however I can only iterate over it once because it consumes the struct when iterating.

How should I make it so my function can loop twice? I know I could use values: Vec<usize> however I would like to make it generic over any object that is iterable.

Here’s an example of what I would like to do: (Please ignore what the loops are actually doing. In my real code I can’t condense the two loops into one.)

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

fn perform<'a, I>(values: I) -> usize
where
    I: Iterator<Item = &'a usize>,
{
    // Loop one: This works.
    let sum = values.sum::<usize>();

    // Loop two: This doesn't work due to `error[E0382]: use of moved value: 
    // `values``.
    let max = values.max().unwrap();
    sum * max
}

fn main() {
    let v: Vec<usize> = vec![1, 2, 3, 4];

    let result = perform(v.iter());
    print!("Result: {}", result);
}

>Solution :

You can’t iterate over the same iterator twice, because iterators are not guaranteed to be randomly accessible. For example, std::iter::from_fn produces an iterator that is most definitely not randomly accessible.

As @mousetail already mentioned, one way to get around this problem is to expect a Cloneable iterator:

fn perform<'a, I>(values: I) -> usize
where
    I: Iterator<Item = &'a usize> + Clone,
{
    // Loop one: This works.
    let sum = values.clone().sum::<usize>();

    // Loop two: This doesn't work due to `error[E0382]: use of moved value:
    // `values``.
    let max = values.max().unwrap();
    sum * max
}

fn main() {
    let v: Vec<usize> = vec![1, 2, 3, 4];

    let result = perform(v.iter());
    println!("Result: {}", result);
}
Result: 40

Although in your specific example, I’d compute both sum and max in the same iteration:

fn perform<'a, I>(values: I) -> usize
where
    I: Iterator<Item = &'a usize>,
{
    let (sum, max) = values.fold((0, usize::MIN), |(sum, max), &el| {
        (sum + el, usize::max(max, el))
    });

    sum * max
}

fn main() {
    let v: Vec<usize> = vec![1, 2, 3, 4];

    let result = perform(v.iter());
    println!("Result: {}", result);
}
Result: 40
Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading