Optionally reverse iterator


#1

I would like to optionally reverse an iterator, like this. But the types in my construction are incompatible:

error[E0308]: if and else have incompatible types
 --> src/main.rs:4:16
  |
4 |       let iter = if reversed {
  |  ________________^
5 | |         v.iter().rev()
6 | |     } else {
7 | |         v.iter()
8 | |     };
  | |_____^ expected struct `std::iter::Rev`, found struct `std::slice::Iter`
  |
  = note: expected type `std::iter::Rev<std::slice::Iter<'_, _>>`
             found type `std::slice::Iter<'_, _>`

The reason not to use reverse() is that I would like to do some further processing of the items via map() and then extend another vector with the items. An intermediate collect() and reverse() would be less efficient. How would I accomplish this?


#2

You can Box the iterator, but that adds some overhead, too. The next fn has to be called through a vtable, which is also harder for the compiler to optimize since the compiler is unlikely to be able to do any inlining.

fn main() {
    let my_nums = vec![1,2,3,4];
    
    let my_nums_iter: Box<Iterator<Item=_>> = if my_nums.len() > 4 {
        Box::new(my_nums.iter())
    } else {
        Box::new(my_nums.iter().rev())
    };
    
    for x in my_nums_iter {
        println!("{}", x);
    }
}

You’d have to test to to see if doing an intermediate collect and reverse is more or less efficient than the boxed iterator.


#3

Boxing is usually reasonably cheap.

Anyway, the alternative is using the either crate.


#4

Alternatively, use https://docs.rs/either crate.

You get this error because each iterator (each combination of iterators) is a different type, and Rust wants to optimize your code for one specific type.


#5

Thank you for your answers! I tried the either-variant first. In my processing step of the items I need the chunk_exact function but it does not seem to exist, link.


#6

You won’t be able to call chunks_exact on an Iterator at all - it’s only a method on slices.


#7

Ok, now I got something that looks good to me, link. Instead of chunks_exact I use tuples() from the itertools crate.


#8

Two small things: you don’t need into_iter() since Either implements Iterator when both items are iterators, and since you are already using itertools, you can use collect_vec() to avoid having to annotate the type. (And yes, itertools is awesome.)


#9

Neat! Thanks for the hints :slight_smile: