diff --git a/src/adaptors/multi_product.rs b/src/adaptors/multi_product.rs index a6796386e..4e53475fa 100644 --- a/src/adaptors/multi_product.rs +++ b/src/adaptors/multi_product.rs @@ -1,32 +1,35 @@ #![cfg(feature = "use_std")] +use std::iter::FromIterator; +use std::marker::PhantomData; use size_hint; -use Itertools; #[derive(Clone)] /// An iterator adaptor that iterates over the cartesian product of /// multiple iterators of type `I`. /// -/// An iterator element type is `Vec<I>`. +/// An iterator element type is `T<I>`, which defaults to `Vec<I>`. /// /// See [`.multi_cartesian_product()`](../trait.Itertools.html#method.multi_cartesian_product) /// for more information. #[must_use = "iterator adaptors are lazy and do nothing unless consumed"] -pub struct MultiProduct<I>(Vec<MultiProductIter<I>>) +pub struct MultiProduct<I, T=Vec<<I as Iterator>::Item>>(Vec<MultiProductIter<I>>, PhantomData<T>) where I: Iterator + Clone, - I::Item: Clone; + I::Item: Clone, + T: FromIterator<I::Item>; /// Create a new cartesian product iterator over an arbitrary number /// of iterators of the same type. /// -/// Iterator element is of type `Vec<H::Item::Item>`. -pub fn multi_cartesian_product<H>(iters: H) -> MultiProduct<<H::Item as IntoIterator>::IntoIter> +/// Iterator element is of type `T<H::Item::Item>`. +pub fn multi_cartesian_product<H, T>(iters: H) -> MultiProduct<<H::Item as IntoIterator>::IntoIter, T> where H: Iterator, H::Item: IntoIterator, <H::Item as IntoIterator>::IntoIter: Clone, - <H::Item as IntoIterator>::Item: Clone + <H::Item as IntoIterator>::Item: Clone, + T: FromIterator<<H::Item as IntoIterator>::Item> { - MultiProduct(iters.map(|i| MultiProductIter::new(i.into_iter())).collect()) + MultiProduct(iters.map(|i| MultiProductIter::new(i.into_iter())).collect(), PhantomData) } #[derive(Clone, Debug)] @@ -47,9 +50,10 @@ enum MultiProductIterState { MidIter { on_first_iter: bool }, } -impl<I> MultiProduct<I> +impl<I, T> MultiProduct<I, T> where I: Iterator + Clone, - I::Item: Clone + I::Item: Clone, + T: FromIterator<I::Item> { /// Iterates the rightmost iterator, then recursively iterates iterators /// to the left if necessary. @@ -77,7 +81,7 @@ impl<I> MultiProduct<I> if last.in_progress() { true - } else if MultiProduct::iterate_last(rest, state) { + } else if Self::iterate_last(rest, state) { last.reset(); last.iterate(); // If iterator is None twice consecutively, then iterator is @@ -97,7 +101,7 @@ impl<I> MultiProduct<I> } /// Returns the unwrapped value of the next iteration. - fn curr_iterator(&self) -> Vec<I::Item> { + fn curr_iterator(&self) -> T { self.0.iter().map(|multi_iter| { multi_iter.cur.clone().unwrap() }).collect() @@ -143,14 +147,15 @@ impl<I> MultiProductIter<I> } } -impl<I> Iterator for MultiProduct<I> +impl<I, T> Iterator for MultiProduct<I, T> where I: Iterator + Clone, - I::Item: Clone + I::Item: Clone, + T: FromIterator<I::Item> { - type Item = Vec<I::Item>; + type Item = T; fn next(&mut self) -> Option<Self::Item> { - if MultiProduct::iterate_last( + if Self::iterate_last( &mut self.0, MultiProductIterState::StartOfIter ) { @@ -204,17 +209,8 @@ impl<I> Iterator for MultiProduct<I> } fn last(self) -> Option<Self::Item> { - let iter_count = self.0.len(); - - let lasts: Self::Item = self.0.into_iter() + self.0.into_iter() .map(|multi_iter| multi_iter.iter.last()) - .while_some() - .collect(); - - if lasts.len() == iter_count { - Some(lasts) - } else { - None - } + .collect() } } diff --git a/src/lib.rs b/src/lib.rs index aa01a4f91..6cc861584 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -890,11 +890,48 @@ pub trait Itertools : Iterator { /// assert_eq!(multi_prod.next(), None); /// ``` #[cfg(feature = "use_std")] - fn multi_cartesian_product(self) -> MultiProduct<<Self::Item as IntoIterator>::IntoIter> + fn multi_cartesian_product(self) -> MultiProduct<<Self::Item as IntoIterator>::IntoIter, Vec<<Self::Item as IntoIterator>::Item>> where Self: Iterator + Sized, Self::Item: IntoIterator, <Self::Item as IntoIterator>::IntoIter: Clone, - <Self::Item as IntoIterator>::Item: Clone + <Self::Item as IntoIterator>::Item: Clone, + { + self.multi_cartesian_product_with() + } + + /// Return an iterator adaptor that iterates over the cartesian product of + /// all subiterators returned by meta-iterator `self`. + /// + /// All provided iterators must yield the same `Item` type. To generate + /// the product of iterators yielding multiple types, use the + /// [`iproduct`](macro.iproduct.html) macro instead. + /// + /// + /// The iterator element type is `C<T>`, where `T` is the iterator element + /// of the subiterators. + /// + /// ``` + /// use std::collections::VecDeque; + /// use itertools::Itertools; + /// let mut multi_prod = (0..3).map(|i| (i * 2)..(i * 2 + 2)) + /// .multi_cartesian_product_with::<VecDeque<i32>>(); + /// assert_eq!(multi_prod.next(), Some(vec![0, 2, 4].into())); + /// assert_eq!(multi_prod.next(), Some(vec![0, 2, 5].into())); + /// assert_eq!(multi_prod.next(), Some(vec![0, 3, 4].into())); + /// assert_eq!(multi_prod.next(), Some(vec![0, 3, 5].into())); + /// assert_eq!(multi_prod.next(), Some(vec![1, 2, 4].into())); + /// assert_eq!(multi_prod.next(), Some(vec![1, 2, 5].into())); + /// assert_eq!(multi_prod.next(), Some(vec![1, 3, 4].into())); + /// assert_eq!(multi_prod.next(), Some(vec![1, 3, 5].into())); + /// assert_eq!(multi_prod.next(), None); + /// ``` + #[cfg(feature = "use_std")] + fn multi_cartesian_product_with<C>(self) -> MultiProduct<<Self::Item as IntoIterator>::IntoIter, C> + where Self: Iterator + Sized, + Self::Item: IntoIterator, + <Self::Item as IntoIterator>::IntoIter: Clone, + <Self::Item as IntoIterator>::Item: Clone, + C: FromIterator<<Self::Item as IntoIterator>::Item>, { adaptors::multi_cartesian_product(self) }