Skip to content

Allow custom collections for multi cartesian product items #345

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 23 additions & 27 deletions src/adaptors/multi_product.rs
Original file line number Diff line number Diff line change
@@ -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)]
Expand All @@ -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.
Expand Down Expand Up @@ -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
Expand All @@ -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()
Expand Down Expand Up @@ -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
) {
Expand Down Expand Up @@ -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()
}
}
41 changes: 39 additions & 2 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
Expand Down