itertools/
combinations_with_replacement.rs1use alloc::vec::Vec;
2use std::fmt;
3use std::iter::FusedIterator;
4
5use super::lazy_buffer::LazyBuffer;
6
7#[derive(Clone)]
12pub struct CombinationsWithReplacement<I>
13where
14 I: Iterator,
15 I::Item: Clone,
16{
17 indices: Vec<usize>,
18 pool: LazyBuffer<I>,
19 first: bool,
20}
21
22impl<I> fmt::Debug for CombinationsWithReplacement<I>
23where
24 I: Iterator + fmt::Debug,
25 I::Item: fmt::Debug + Clone,
26{
27 debug_fmt_fields!(Combinations, indices, pool, first);
28}
29
30impl<I> CombinationsWithReplacement<I>
31where
32 I: Iterator,
33 I::Item: Clone,
34{
35 fn current(&self) -> Vec<I::Item> {
37 self.indices.iter().map(|i| self.pool[*i].clone()).collect()
38 }
39}
40
41pub fn combinations_with_replacement<I>(iter: I, k: usize) -> CombinationsWithReplacement<I>
43where
44 I: Iterator,
45 I::Item: Clone,
46{
47 let indices: Vec<usize> = alloc::vec![0; k];
48 let pool: LazyBuffer<I> = LazyBuffer::new(iter);
49
50 CombinationsWithReplacement {
51 indices,
52 pool,
53 first: true,
54 }
55}
56
57impl<I> Iterator for CombinationsWithReplacement<I>
58where
59 I: Iterator,
60 I::Item: Clone,
61{
62 type Item = Vec<I::Item>;
63 fn next(&mut self) -> Option<Self::Item> {
64 if self.first {
66 return if !(self.indices.is_empty() || self.pool.get_next()) {
68 None
69 } else {
71 self.first = false;
72 Some(self.current())
73 };
74 }
75
76 self.pool.get_next();
79
80 let mut increment: Option<(usize, usize)> = None;
82 for (i, indices_int) in self.indices.iter().enumerate().rev() {
83 if *indices_int < self.pool.len()-1 {
84 increment = Some((i, indices_int + 1));
85 break;
86 }
87 }
88
89 match increment {
90 Some((increment_from, increment_value)) => {
92 for indices_index in increment_from..self.indices.len() {
95 self.indices[indices_index] = increment_value;
96 }
97 Some(self.current())
98 }
99 None => None,
101 }
102 }
103}
104
105impl<I> FusedIterator for CombinationsWithReplacement<I>
106where
107 I: Iterator,
108 I::Item: Clone,
109{}