Use iterator or collected vec

I'm using iproduct iterator which takes two iterators and return cross product. The second param must me clonable.

I'd like to sometimes pass an iterator as the second argument, and sometimes collect it for perfomance improvements. This is my code (playground):

use itertools::iproduct;

fn main() {
    let left_part = (1..10).into_iter();
    let it = (1..10).into_iter();
    let collect = true;
    let right_part = if collect { it.collect::<Vec<i32>>() } else { it };
    let cross_product = iproduct!(left_part, right_part);    
}

The problem is that if/else have incompatible types. If I put it inside a Box and say that both of them implement Clone trait it's throwing error. How could I solve it?

Thanks in advance

I'd write a generic function like this:

use itertools::iproduct;

pub fn prod<X: Clone, Y, J: IntoIterator<Item = Y>>(
    i: impl Iterator<Item = X>,
    j: J,
) -> impl Iterator<Item = (X, Y)>
where
    J::IntoIter: Clone,
{
    iproduct!(i, j.into_iter())
}

(playground)

Then you can do

    let cross_product = if collect { prod(left_part, it.collect::<Vec<_>>()) } else { prod(left_part, it) };

Actually an even simpler solution would be

macro_rules! prod {
    ( $i:expr, $j:expr ) => { itertools::iproduct!($i, $j.into_iter()) };
}
2 Likes

Cool! Thank you so much!