MAG
MAG

Reputation: 474

Is there a function in Rust equivalent to Java's Stream.Iterate?

Does the Rust standard library have a function that generates an infinite iterator given a seed and a lambda, as the Java 8 Streams provide? If not, what is a similar alternative in Rust?

Stream.iterate(1, x -> 2 * x);

Upvotes: 10

Views: 2174

Answers (4)

Mutant Bob
Mutant Bob

Reputation: 3549

I wonder if

fn main() {
    let x = (1..std::i32::MAX) .map(|x| x*2);

    for i in x {
        println!("{}", i);
    }
}

would be a satisfactory option for you.

Upvotes: 0

aSpex
aSpex

Reputation: 5216

You can use standard scan iterator:

let seq_gen = iter::repeat(())
                      .scan(1, |r,_|{
                          let out = *r; *r = out * 2 ; Some(out)
                      });

or with explicit closure definition:

let seq_gen = iter::repeat(())
                      .scan((1, |x| x*2), |r,_|{
                          let out = r.0; r.0 = r.1(r.0); Some(out)
                      });

For noncopyable types things looks worse:

let seq_gen = iter::repeat(())
                      .scan(Some("Hello world".to_owned()), |r,_|{
                          let out = r.clone(); *r = r.take().map(|x| x+"!") ; out
                      });

For these types it is better to use functions that modify the value in place:

let seq_gen = iter::repeat(())
                      .scan("Hello world".to_owned(), |r,_|{
                          let out = r.clone(); r.push_str("!") ; Some(out)
                      });

Upvotes: 2

Shepmaster
Shepmaster

Reputation: 430318

The Rust standard library used to have similar functionality under the name unfold, but it was never made stable and was eventually removed. It now lives in the itertools crate:

extern crate itertools;

use itertools::Unfold;

fn main() {
    let x = Unfold::new(1, |x| {
        *x *= 2;
        Some(*x)
    });

    for val in x.take(10) {
        println!("{}", val);
    }
}

Note that it's a bit more complicated because the state doesn't have to exactly match with what the iterator returns and you can control when the iterator stops. It's possible that the crate would accept a PR for a thin layer on top that gives your exact implementation.

Upvotes: 8

Francis Gagné
Francis Gagné

Reputation: 65692

As of Rust 1.7, there's nothing in Rust's standard library that does the equivalent of Stream.iterate (or I couldn't find it!).

I just whipped up the following implementation in Rust. It's not as straightforward as the Java implementation might be, because we have to take care of ownership (hence the requirement for Clone and the Option dance with the value field).

struct SequenceGenerator<T, F> {
    value: Option<T>,
    calc_next: F,
}

impl<T, F> SequenceGenerator<T, F>
    where T: Clone,
          F: FnMut(T) -> T
{
    fn new(value: T, calc_next: F) -> SequenceGenerator<T, F> {
        SequenceGenerator {
            value: Some(value),
            calc_next: calc_next,
        }
    }
}

impl<T, F> Iterator for SequenceGenerator<T, F>
    where T: Clone,
          F: FnMut(T) -> T
{
    type Item = T;

    fn next(&mut self) -> Option<T> {
        let result = self.value.as_ref().unwrap().clone();
        self.value = Some((self.calc_next)(self.value.take().unwrap()));
        Some(result)
    }
}

fn main() {
    let seq_gen = SequenceGenerator::new(1, |x| 2 * x);
    for i in seq_gen.take(10) {
        println!("{}", i);
    }
}

Upvotes: 7

Related Questions