16

How should I go if I want to iterate with a custom step in stable Rust? Essentially something like the C/C++

for (int i = 0; i < n; i += 2) {

}

I've already tried using range_step_inclusive and the solutions in How do I iterate over a range with a custom step?:

use std::iter::range_step_inclusive;
for i in range_step_inclusive(0, n, 2) {
    println!("i: {}", i);
}

But it seems like it isn't available in Rust 1.1:

error: unresolved import `std::iter::range_step_inclusive`. There is no `range_step_inclusive` in `std::iter`

What would be an alternative? Possibly the idiomatic way for creating custom ranges.

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
Vale
  • 1,912
  • 16
  • 22
  • 1
    I edited your title to clarify that you are looking for a solution that applies to **stable** Rust, as otherwise this would [be a dupe](http://stackoverflow.com/q/27893223/155423). – Shepmaster Jul 12 '15 at 19:17
  • 1
    Possible duplicate of [How do I iterate over a range with a custom step?](http://stackoverflow.com/questions/27893223/how-do-i-iterate-over-a-range-with-a-custom-step) – cambunctious Apr 08 '17 at 04:16

6 Answers6

18

Rust 1.28+

Iterator::step_by is now stable:

fn main() {
    for i in (0..100).step_by(2) {
        println!("{}", i);
    }
}

Rust 1.1+

You can always write it out the old-fashioned way:

fn main() {
    let mut i = 0;
    while i < 100 {
        println!("i: {}", i);
        i += 2;
    }
}

Which can then be abstracted:

use std::ops::Add;

fn step_by<T, F>(start: T, end_exclusive: T, step: T, mut body: F)
where
    T: Add<Output = T> + PartialOrd + Copy,
    F: FnMut(T),
{
    let mut i = start;
    while i < end_exclusive {
        body(i);
        i = i + step;
    }
}

fn main() {
    step_by(0, 100, 2, |i| {
        println!("i: {}", i);
    })
}

Interesting historical side note, I believe that originally all the looping was done with closures like this, before iterators became extremely prevalent.

You can then take this and make it into an iterator:

use std::ops::Add;

struct StepBy<T> {
    start: T,
    end_exclusive: T,
    step: T,
}

impl<T> StepBy<T> {
    fn new(start: T, end_exclusive: T, step: T) -> Self {
        Self {
            start,
            end_exclusive,
            step,
        }
    }
}

impl<T> Iterator for StepBy<T>
where
    T: Add<Output = T> + PartialOrd + Copy,
{
    type Item = T;
    fn next(&mut self) -> Option<Self::Item> {
        if self.start < self.end_exclusive {
            let v = self.start;
            self.start = self.start + self.step;
            Some(v)
        } else {
            None
        }
    }
}

fn main() {
    for i in StepBy::new(0, 100, 2) {
        println!("i: {}", i);
    }
}

See also:

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
  • 1
    I was hoping for a more "elegant" and built-in solution but I guess that's what happens with new(ish) languages. Thanks! – Vale Jul 12 '15 at 19:43
  • 1
    @Sosdoc stepping by an increment is a highly anticipated addition! It just turns out to be complicated. What do you do for edge cases like exceeding the bounds of your type in either direction? Or handling stepping by zero? It's surprising the little details that are possible. Note that my solution has nothing to prevent you from misusing it. :-) – Shepmaster Jul 12 '15 at 19:57
  • 1
    I know, I was just a bit perplexed that I couldn't find something I had been used to since I was fiddling with C. – Vale Jul 12 '15 at 20:16
  • 1
    You can always use `for i in 0..(n/2) { let i = i * 2; … }` – Hauleth Jul 12 '15 at 20:27
  • Still very useful, as `Iterator::step_by` forces us to use 64 bits, this is faster when we're sure we can stick with 32 bits. – simonzack Sep 10 '20 at 15:57
5

There is way using let "redefinition":

for i in 0..((n + 1) / 2) {
    let i = i * 2;
    // …
}

Or use Iterator::map:

for i in (0..((n + 1) / 2)).map(|i| i * 2) {
    // …
}
Hauleth
  • 22,873
  • 4
  • 61
  • 112
3

I think i'll stick to a while loop. But if you really want an iterator based method you could try this

fn main(){
    let (start, step, end) = (1, 2, 20);
    for i in (0..).map(|x| start+step*x)
                  .take_while(|&x| x<end){
        println!("{:?}", i);
    }
}
basic_bgnr
  • 697
  • 5
  • 14
3

Use the crate num

Cargo.toml:

[dependencies.num]
version = "0.1.25"
default-features = false

Since you only need the crate's basics, use default-features = false.

Rust:

extern crate num;

use num::range_step;

for i in range_step(0, 10, 2) {
    /*    */
}

range_step is generic over rust's integer types.

bluss
  • 12,472
  • 1
  • 49
  • 48
3

Since this question was asked, the itertools crate, has become fairly standard as a dependency. You can do what you want very simply with the step() method:

extern crate itertools; // 0.7.8
use itertools::Itertools;

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

In your Cargo.toml:

[dependencies]
itertools = "0.7.8"
Peter Hall
  • 53,120
  • 14
  • 139
  • 204
-1

You can use the iterator_step_by feature.

Here is an example of two threads running, one of them printing out odd numbers and the other even ones:

#![feature(iterator_step_by)]
extern crate thebook;

use std::thread;
use std::time::Duration;
fn main() {
    let handle = thread::spawn(|| {
        for i in (1..1000).step_by(2) {
            println!("{}", i);
        }
    });
    for i in (2..1000).step_by(2) {
        println!("{}", i);
    }
    handle.join();
}

Without this feature, you can also use a filter on the range:

use std::thread;
use std::time::Duration;
fn main() {
    let handle = thread::spawn(|| {
        for i in (1..1000).filter(|x| x % 2 != 0) {
            println!("{}", i);
        }
    });
    for i in (2..1000).filter(|x| x % 2 == 0) {
        println!("{}", i);
    }
    handle.join();
}
qed
  • 22,298
  • 21
  • 125
  • 196