use alloc::vec::Vec;
use std::fmt;
use std::iter::FusedIterator;
use super::lazy_buffer::LazyBuffer;
#[derive(Clone)]
pub struct CombinationsWithReplacement<I>
where
I: Iterator,
I::Item: Clone,
{
indices: Vec<usize>,
pool: LazyBuffer<I>,
first: bool,
}
impl<I> fmt::Debug for CombinationsWithReplacement<I>
where
I: Iterator + fmt::Debug,
I::Item: fmt::Debug + Clone,
{
debug_fmt_fields!(Combinations, indices, pool, first);
}
impl<I> CombinationsWithReplacement<I>
where
I: Iterator,
I::Item: Clone,
{
fn current(&self) -> Vec<I::Item> {
self.indices.iter().map(|i| self.pool[*i].clone()).collect()
}
}
pub fn combinations_with_replacement<I>(iter: I, k: usize) -> CombinationsWithReplacement<I>
where
I: Iterator,
I::Item: Clone,
{
let indices: Vec<usize> = alloc::vec![0; k];
let pool: LazyBuffer<I> = LazyBuffer::new(iter);
CombinationsWithReplacement {
indices,
pool,
first: true,
}
}
impl<I> Iterator for CombinationsWithReplacement<I>
where
I: Iterator,
I::Item: Clone,
{
type Item = Vec<I::Item>;
fn next(&mut self) -> Option<Self::Item> {
if self.first {
return if !(self.indices.is_empty() || self.pool.get_next()) {
None
} else {
self.first = false;
Some(self.current())
};
}
self.pool.get_next();
let mut increment: Option<(usize, usize)> = None;
for (i, indices_int) in self.indices.iter().enumerate().rev() {
if *indices_int < self.pool.len()-1 {
increment = Some((i, indices_int + 1));
break;
}
}
match increment {
Some((increment_from, increment_value)) => {
for indices_index in increment_from..self.indices.len() {
self.indices[indices_index] = increment_value;
}
Some(self.current())
}
None => None,
}
}
}
impl<I> FusedIterator for CombinationsWithReplacement<I>
where
I: Iterator,
I::Item: Clone,
{}