I'm answering this question after 4 years both because the accepted answer is too convoluted, and due to the fact that Python's itertools.product
is a generic function (whereas the accepted answer works only for String
s).
Moreover, notice that the kproduct
function defined in the accepted answer is recursive, and Rust doesn't guarantee tail-call optimization.
Using the third-party itertools crate, we can define a product_repeat
function in two ways: either by defining a standard top-level function, or by adding a ProductRepeat
trait for all Iterator
s.
This is the top-level function:
use itertools::{Itertools, MultiProduct};
/// Rust version of Python's itertools.product().
/// It returns the cartesian product of the input iterables, and it is
/// semantically equivalent to `repeat` nested for loops.
///
/// # Arguments
///
/// * `it` - An iterator over a cloneable data structure
/// * `repeat` - Number of repetitions of the given iterator
pub fn product_repeat<I>(it: I, repeat: usize) -> MultiProduct<I>
where
I: Iterator + Clone,
I::Item: Clone {
std::iter::repeat(it)
.take(repeat)
.multi_cartesian_product()
}
If you instead prefer augmenting the Iterator trait, you can do it as follows:
pub trait ProductRepeat: Iterator + Clone
where Self::Item: Clone {
fn product_repeat(self, repeat: usize) -> MultiProduct<Self> {
std::iter::repeat(self)
.take(repeat)
.multi_cartesian_product()
}
}
impl<T: Iterator + Clone> ProductRepeat for T
where T::Item: Clone {}
Here is a demo in the Rust playground.