itertools/
combinations.rs1use alloc::boxed::Box;
2use core::array;
3use core::borrow::BorrowMut;
4use std::fmt;
5use std::iter::FusedIterator;
6
7use super::lazy_buffer::LazyBuffer;
8use alloc::vec::Vec;
9
10use crate::adaptors::checked_binomial;
11
12pub type Combinations<I> = CombinationsGeneric<I, Vec<usize>>;
14pub type ArrayCombinations<I, const K: usize> = CombinationsGeneric<I, [usize; K]>;
16
17pub fn combinations<I: Iterator>(iter: I, k: usize) -> Combinations<I>
19where
20 I::Item: Clone,
21{
22 Combinations::new(iter, (0..k).collect())
23}
24
25pub fn array_combinations<I: Iterator, const K: usize>(iter: I) -> ArrayCombinations<I, K>
27where
28 I::Item: Clone,
29{
30 ArrayCombinations::new(iter, array::from_fn(|i| i))
31}
32
33#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
37pub struct CombinationsGeneric<I: Iterator, Idx> {
38 indices: Idx,
39 pool: LazyBuffer<I>,
40 first: bool,
41}
42
43pub trait PoolIndex<T>: BorrowMut<[usize]> {
46 type Item;
47
48 fn extract_item<I: Iterator<Item = T>>(&self, pool: &LazyBuffer<I>) -> Self::Item
49 where
50 T: Clone;
51
52 fn len(&self) -> usize {
53 self.borrow().len()
54 }
55}
56impl<T> PoolIndex<T> for Box<[usize]> {
57 type Item = Vec<T>;
58
59 fn extract_item<I: Iterator<Item = T>>(&self, pool: &LazyBuffer<I>) -> Vec<T>
60 where
61 T: Clone,
62 {
63 pool.get_at(self)
64 }
65}
66impl<T> PoolIndex<T> for Vec<usize> {
67 type Item = Vec<T>;
68
69 fn extract_item<I: Iterator<Item = T>>(&self, pool: &LazyBuffer<I>) -> Vec<T>
70 where
71 T: Clone,
72 {
73 pool.get_at(self)
74 }
75}
76
77impl<T, const K: usize> PoolIndex<T> for [usize; K] {
78 type Item = [T; K];
79
80 fn extract_item<I: Iterator<Item = T>>(&self, pool: &LazyBuffer<I>) -> [T; K]
81 where
82 T: Clone,
83 {
84 pool.get_array(*self)
85 }
86}
87
88impl<I, Idx> Clone for CombinationsGeneric<I, Idx>
89where
90 I: Iterator + Clone,
91 I::Item: Clone,
92 Idx: Clone,
93{
94 clone_fields!(indices, pool, first);
95}
96
97impl<I, Idx> fmt::Debug for CombinationsGeneric<I, Idx>
98where
99 I: Iterator + fmt::Debug,
100 I::Item: fmt::Debug,
101 Idx: fmt::Debug,
102{
103 debug_fmt_fields!(Combinations, indices, pool, first);
104}
105
106impl<I: Iterator, Idx: PoolIndex<I::Item>> CombinationsGeneric<I, Idx> {
107 fn new(iter: I, indices: Idx) -> Self {
109 Self {
110 indices,
111 pool: LazyBuffer::new(iter),
112 first: true,
113 }
114 }
115
116 #[inline]
118 pub fn k(&self) -> usize {
119 self.indices.len()
120 }
121
122 #[inline]
125 pub fn n(&self) -> usize {
126 self.pool.len()
127 }
128
129 #[inline]
131 pub(crate) fn src(&self) -> &LazyBuffer<I> {
132 &self.pool
133 }
134
135 pub(crate) fn n_and_count(self) -> (usize, usize) {
137 let Self {
138 indices,
139 pool,
140 first,
141 } = self;
142 let n = pool.count();
143 (n, remaining_for(n, first, indices.borrow()).unwrap())
144 }
145
146 fn init(&mut self) -> bool {
149 self.pool.prefill(self.k());
150 let done = self.k() > self.n();
151 if !done {
152 self.first = false;
153 }
154
155 done
156 }
157
158 fn increment_indices(&mut self) -> bool {
164 let indices = self.indices.borrow_mut();
166
167 if indices.is_empty() {
168 return true; }
170 let mut i: usize = indices.len() - 1;
172
173 if indices[i] == self.pool.len() - 1 {
175 self.pool.get_next(); }
177
178 while indices[i] == i + self.pool.len() - indices.len() {
179 if i > 0 {
180 i -= 1;
181 } else {
182 return true;
184 }
185 }
186
187 indices[i] += 1;
189 for j in i + 1..indices.len() {
190 indices[j] = indices[j - 1] + 1;
191 }
192 false
194 }
195
196 pub(crate) fn try_nth(&mut self, n: usize) -> Result<<Self as Iterator>::Item, usize>
198 where
199 I: Iterator,
200 I::Item: Clone,
201 {
202 let done = if self.first {
203 self.init()
204 } else {
205 self.increment_indices()
206 };
207 if done {
208 return Err(0);
209 }
210 for i in 0..n {
211 if self.increment_indices() {
212 return Err(i + 1);
213 }
214 }
215 Ok(self.indices.extract_item(&self.pool))
216 }
217}
218
219impl<I, Idx> Iterator for CombinationsGeneric<I, Idx>
220where
221 I: Iterator,
222 I::Item: Clone,
223 Idx: PoolIndex<I::Item>,
224{
225 type Item = Idx::Item;
226 fn next(&mut self) -> Option<Self::Item> {
227 let done = if self.first {
228 self.init()
229 } else {
230 self.increment_indices()
231 };
232
233 if done {
234 return None;
235 }
236
237 Some(self.indices.extract_item(&self.pool))
238 }
239
240 fn nth(&mut self, n: usize) -> Option<Self::Item> {
241 self.try_nth(n).ok()
242 }
243
244 fn size_hint(&self) -> (usize, Option<usize>) {
245 let (mut low, mut upp) = self.pool.size_hint();
246 low = remaining_for(low, self.first, self.indices.borrow()).unwrap_or(usize::MAX);
247 upp = upp.and_then(|upp| remaining_for(upp, self.first, self.indices.borrow()));
248 (low, upp)
249 }
250
251 #[inline]
252 fn count(self) -> usize {
253 self.n_and_count().1
254 }
255}
256
257impl<I, Idx> FusedIterator for CombinationsGeneric<I, Idx>
258where
259 I: Iterator,
260 I::Item: Clone,
261 Idx: PoolIndex<I::Item>,
262{
263}
264
265impl<I: Iterator> Combinations<I> {
266 pub(crate) fn reset(&mut self, k: usize) {
271 self.first = true;
272
273 if k < self.indices.len() {
274 self.indices.truncate(k);
275 for i in 0..k {
276 self.indices[i] = i;
277 }
278 } else {
279 for i in 0..self.indices.len() {
280 self.indices[i] = i;
281 }
282 self.indices.extend(self.indices.len()..k);
283 self.pool.prefill(k);
284 }
285 }
286}
287
288fn remaining_for(n: usize, first: bool, indices: &[usize]) -> Option<usize> {
290 let k = indices.len();
291 if n < k {
292 Some(0)
293 } else if first {
294 checked_binomial(n, k)
295 } else {
296 indices.iter().enumerate().try_fold(0usize, |sum, (i, n0)| {
315 sum.checked_add(checked_binomial(n - 1 - *n0, k - i)?)
316 })
317 }
318}