rust-itertools / itertools

Extra iterator adaptors, iterator methods, free functions, and macros.
https://docs.rs/itertools/
Apache License 2.0
2.72k stars 309 forks source link

Make a Product adapter for the Itertools trait #10

Closed alexchandel closed 9 years ago

alexchandel commented 9 years ago

In addition to iproduct!(iter_a, iter_b), Itertools should have something like iter_a.times(iter_b) or iter_a.cartesian_product(iter_b). This would let you take the product of iterators inline, functional style.

Maybe a method like this:

pub trait Itertools: Iterator {
    ...
    fn cartesian_product<U: Iterator>(self, other: U) -> Product<Item, Self, U> 

This would allow you to do much better inline operations, like:

oranges.iter().map(apple_for_orange).filter(is_granny_smith).cartesian_product(
    guests.iter().map(favorite_desert)
).map(more_nonsense).etc()

This shouldn't require higher-kinded types either.

bluss commented 9 years ago

An adaptor for product is a good idea, I guess it's the most natural way to use it. Not sure if we can make it expand tuples like the iproduct macro does (((x, y), z) → (x, y, z)).

alexchandel commented 9 years ago

That would be preferable, but I think it requires variadic generics, or at minimum having two impls, one for Item=A and one for Item=(A,B).

I'd be satisfied with the basics for now. I can always map(|((x,y),z)| (x,y,z)) until then.

bluss commented 9 years ago

Is there any reason to prefer the long name cartesian_product? I.e. are there other products we might want to add?

alexchandel commented 9 years ago

@bluss Can't think of any others (not that there aren't any), but we want to avoid product() because it's taken by MultiplicativeIterator. times() would work too, though it's less specific.

FranklinChen commented 9 years ago

Something else very useful is a Cartesian product without a hardcoded length, i.e., concretely something like taking a vector of iterators and returning a iterator of vectors: a form of Haskell's sequenceA, where

sequenceA [[0..2], [0..2], [0..2]] == [[0,0,0],[0,0,1],[0,0,2],[0,1,0],[0,1,1],[0,1,2],[0,2,0],[0,2,1],[0,2,2],[1,0,0],[1,0,1],[1,0,2],[1,1,0],[1,1,1],[1,1,2],[1,2,0],[1,2,1],[1,2,2],[2,0,0],[2,0,1],[2,0,2],[2,1,0],[2,1,1],[2,1,2],[2,2,0],[2,2,1],[2,2,2]]