Reputation: 14226
I want to start with a base value of 1
and then multiply my base value by 2
each iteration up to a defined limit (say the total length of my array).
Do I have to implement a special iterator just to do this? Or can I combine other iterator methods like map
and filter
together in order to achieve the same functionality. Though I would imagine implementing my iterator specifically would be more efficient, but also more verbose.
Upvotes: 0
Views: 343
Reputation: 430320
You can use Iterator::scan
:
use std::iter;
fn main() {
let items = iter::repeat(()).scan(1i32, |state, _| {
let current_state = *state;
*state = current_state * 2;
Some(current_state)
});
println!("{:?}", items.take(10).collect::<Vec<_>>());
}
This has a small state which starts with your initial value (1i32
) and doubles the state each time, returning the previous one.
Since closures capture their environment, you can do this without scan
, although I like my iterators to contain all the info they need, so I'd be unlikely to actually do this:
let mut state = 1;
let items = iter::repeat(()).map(|_| {
let v = state;
state *= 2;
v
});
And there's always the long-form:
struct Doubling {
value: i32,
}
impl Doubling {
fn new(value: i32) -> Self {
Self { value }
}
}
impl Iterator for Doubling {
type Item = i32;
fn next(&mut self) -> Option<Self::Item> {
let val = self.value;
self.value *= 2;
Some(val)
}
}
fn main() {
let items = Doubling::new(1);
println!("{:?}", items.take(10).collect::<Vec<_>>());
}
Upvotes: 5
Reputation: 22163
You could do the following:
fn main() {
for i in (0..).map(|n| 2usize.pow(n)).take(10) { // take(10) so it stops
println!("{}", i);
}
}
Output:
1
2
4
8
16
32
64
128
256
512
It's pretty efficient, there's no need to implement your own iterator for this.
Upvotes: 5