How do I iterate over a range with a custom step?

Rust

Rust Problem Overview


How can I iterate over a range in Rust with a step other than 1? I'm coming from a C++ background so I'd like to do something like

for(auto i = 0; i <= n; i+=2) {
    //...
}

In Rust I need to use the range function, and it doesn't seem like there is a third argument available for having a custom step. How can I accomplish this?

Rust Solutions


Solution 1 - Rust

range_step_inclusive and range_step are long gone.

As of Rust 1.28, Iterator::step_by is stable:

fn main() {
    for x in (1..10).step_by(2) {
        println!("{}", x);
    }
}

Solution 2 - Rust

It seems to me that until the .step_by method is made stable, one can easily accomplish what you want with an Iterator (which is what Ranges really are anyway):

struct SimpleStepRange(isize, isize, isize);  // start, end, and step

impl Iterator for SimpleStepRange {
    type Item = isize;

    #[inline]
    fn next(&mut self) -> Option<isize> {
        if self.0 < self.1 {
            let v = self.0;
            self.0 = v + self.2;
            Some(v)
        } else {
            None
        }
    }
}

fn main() {
    for i in SimpleStepRange(0, 10, 2) {
        println!("{}", i);
    }
}

If one needs to iterate multiple ranges of different types, the code can be made generic as follows:

use std::ops::Add;

struct StepRange<T>(T, T, T)
    where for<'a> &'a T: Add<&'a T, Output = T>,
          T: PartialOrd,
          T: Clone;
          
impl<T> Iterator for StepRange<T>
    where for<'a> &'a T: Add<&'a T, Output = T>,
          T: PartialOrd,
          T: Clone
{
    type Item = T;

    #[inline]
    fn next(&mut self) -> Option<T> {
        if self.0 < self.1 {
            let v = self.0.clone();
            self.0 = &v + &self.2;
            Some(v)
        } else {
            None
        }
    }
}

fn main() {
    for i in StepRange(0u64, 10u64, 2u64) {
        println!("{}", i);
    }
}

I'll leave it to you to eliminate the upper bounds check to create an open ended structure if an infinite loop is required...

Advantages of this approach is that is works with for sugaring and will continue to work even when unstable features become usable; also, unlike the de-sugared approach using the standard Ranges, it doesn't lose efficiency by multiple .next() calls. Disadvantages are that it takes a few lines of code to set up the iterator so may only be worth it for code that has a lot of loops.

Solution 3 - Rust

If you are stepping by something predefined, and small like 2, you may wish to use the iterator to step manually. e.g.:

let mut iter = 1..10;
loop {
    match iter.next() {
        Some(x) => {
            println!("{}", x);
        },
        None => break,
    }
    iter.next();
}

You could even use this to step by an arbitrary amount (although this is definitely getting longer and harder to digest):

let mut iter = 1..10;
let step = 4;
loop {
    match iter.next() {
        Some(x) => {
            println!("{}", x);
        },
        None => break,
    }
    for _ in 0..step-1 {
        iter.next();
    }
}

Solution 4 - Rust

Use the num crate with range_step

Solution 5 - Rust

You'd write your C++ code:

for (auto i = 0; i <= n; i += 2) {
    //...
}

...in Rust like so:

let mut i = 0;
while i <= n {
    // ...
    i += 2;
}

I think the Rust version is more readable too.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionSyntactic FructoseView Question on Stackoverflow
Solution 1 - RustPillView Answer on Stackoverflow
Solution 2 - RustGordonBGoodView Answer on Stackoverflow
Solution 3 - RustLeigh McCullochView Answer on Stackoverflow
Solution 4 - RustcambunctiousView Answer on Stackoverflow
Solution 5 - RustkmkyView Answer on Stackoverflow