Variable or custom step iteration

How to make variable step iteration?
How to extend Iterator trait with custom method?
This solution should be without unnecessary performance penalties.

Desired example:

for i in (1..10).step_by_mul(2) {
    println!("{}", i);
}

Expected:

1 2 4 8

You used to be able to do this with std::iter::iterate or std::iter::Unfold, but these were never stabilized. I think they're now removed altogether.

There is itertools::Unfold, but I don't know if that has a convenient wrapper like we had in std::iter::iterate -- @bluss?

There is the unstable std::iter::StepBy (and associated issue). Last word is that the API still needs some work, and so hasn't entered its final comment period. If you want this to happen, it would be helpful to hear any opinions voiced in the issue thread.

I don't think you are going to find anything "standard". Stepping by an increasing value isn't something that people need very often. Stepping by a fixed amount other than 1 is way more common, and I don't think we even have that. You are going to have to run a while loop:

let i = 1
let step = 1

while i < 10 {
    println!("{}", i);
    i += step;
    step *= 2;
}
1 Like

While loop is a solution but I want to understand is where a iteration way before using it.

impl<T> ExtensionTrait  for T where T: Iterator { }

see itertools for a complete implemention. There might be an iterator adapter that do what you want in itertools as well.

For that sequence in particular you can use (0..10).map(|x| 1 << x)

@cuviper Unfold is the same as it was in libstd, but it's true there is no iterate. It would be easy to add.

1 Like

I've done some solution. It works. But it's good only as a study case. Pixel's solution is much simpler and faster.

use std::ops::{Mul, Range};

struct MulStep<T> {
    step: T,
    pos: T,
    end: T
}

impl<T> Iterator for MulStep<T>
    where T: Copy + Ord + Mul<T, Output = T>
{
    type Item = T;

    fn next(&mut self) -> Option<Self::Item> {
        if self.pos < self.end {
            let result = self.pos;
            self.pos = self.pos * self.step;
            Some(result)
        } else {
            None
        }
    }
}

trait StepByMulExtender<T> {
    fn step_by_mul(self, step: T) -> MulStep<T>;
}

impl<T> StepByMulExtender<T> for Range<T> {
    fn step_by_mul(self, step: T) -> MulStep<T> {
        MulStep {
            step: step,
            pos: self.start,
            end: self.end
        }
    }
}

fn main() {
    for i in (1..10).step_by_mul(2) {
        print!("{} ", i);
    }
}

Result:

1 2 4 8

step_by is now stable, you can do:

for n in (1..10).step_by(2) {  // or (1..=10) depends if you need 10 to be inclusive or exclusive
    println!("{}", n)
}