Troels
Troels

Reputation: 123

Single cyclic iteration from middle of rust vector

I have a vector of some elements that I would like to iterate from some index and cycle around from the front again while only visiting each element a single time.

Ex. starting here at index 2,

[0, 1, 2, 3, 4, 5, 6]
       ^

I would like to have an iterator over the elements [2, 3, 4, 5, 6, 0, 1] (and avoid writing a loop everywhere I need to run through the vector this way). The standard iteration with cycle() + skip() seemed to be a good start, but it of cause never ends.

Is there any idiomatic way with rusts standard iterators?

Upvotes: 3

Views: 1581

Answers (2)

user4815162342
user4815162342

Reputation: 154866

The obvious fix for your cycle/skip combo is to add a take() to limit it:

fn cycle<T>(slice: &[T], start_pos: usize) -> impl Iterator<Item = &T> {
    slice.iter().cycle().skip(start_pos).take(slice.len())
}

Another option is to just chain the two ranges, which even ends up a bit shorter:

fn cycle<T>(slice: &[T], start_pos: usize) -> impl Iterator<Item = &T> {
    slice[start_pos..].iter().chain(&slice[..start_pos])
}

Both versions pass test such as:

let v = vec![0, 1, 2, 3, 4, 5, 6];
assert_eq!(cycle(&v, 2).copied().collect::<Vec<_>>(), vec![2, 3, 4, 5, 6, 0, 1]);

Upvotes: 3

Thomas
Thomas

Reputation: 181725

You can iterate over the two subslices, and use chain to concatenate them together into a single iterator:

let v = vec![0, 1, 2, 3, 4, 5, 6];
let start_index = 2;
for e in v[start_index..].iter().chain(v[..start_index].iter()) {
    println!("{}", e);
}

Upvotes: 3

Related Questions