Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

Tags:

iterator

rust

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);
like image 812
MAG Avatar asked Mar 10 '16 05:03

MAG


People also ask

Is streams better than for loop?

Remember that loops use an imperative style and Streams a declarative style, so Streams are likely to be much easier to maintain. If you have a small list, loops perform better. If you have a huge list, a parallel stream will perform better.

What is the difference between iterator and stream?

Iterators, in Java, are used in Collection Framework to retrieve elements one by one. A stream in Java is a pipeline of objects from an array or a collection data source. A sequential stream is one in which the objects are pipelined in a single stream on the same processing system.

How do I iterate a stream?

List interface provides a stream() method which gives a stream to iterate using forEach method. In forEach method, we can use the lambda expression to iterate over all elements. The following code snippet shows the usage of streams to iterate over the list.

Is stream iterator lazy?

iterator() . The latter will process all items of the stream in order to store them into a collection. In contrast, Stream. iterator() will just return a wrapper around the Stream 's Spliterator which will process all items lazily like all other stream operations do.


2 Answers

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.

like image 71
Shepmaster Avatar answered Oct 18 '22 15:10

Shepmaster


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)
                      });
like image 41
aSpex Avatar answered Oct 18 '22 17:10

aSpex