use alloc::vec::Vec; use std::fmt; use std::iter::once; use std::iter::FusedIterator; use super::lazy_buffer::LazyBuffer; use crate::size_hint::{self, SizeHint}; /// An iterator adaptor that iterates through all the `k`-permutations of the /// elements from an iterator. /// /// See [`.permutations()`](crate::Itertools::permutations) for /// more information. #[must_use = "iterator adaptors are lazy and do nothing unless consumed"] pub struct Permutations { vals: LazyBuffer, state: PermutationState, } impl Clone for Permutations where I: Clone + Iterator, I::Item: Clone, { clone_fields!(vals, state); } #[derive(Clone, Debug)] enum PermutationState { /// No permutation generated yet. Start { k: usize }, /// Values from the iterator are not fully loaded yet so `n` is still unknown. Buffered { k: usize, min_n: usize }, /// All values from the iterator are known so `n` is known. Loaded { indices: Vec, cycles: Vec, }, /// No permutation left to generate. End, } impl fmt::Debug for Permutations where I: Iterator + fmt::Debug, I::Item: fmt::Debug, { debug_fmt_fields!(Permutations, vals, state); } pub fn permutations(iter: I, k: usize) -> Permutations { Permutations { vals: LazyBuffer::new(iter), state: PermutationState::Start { k }, } } impl Iterator for Permutations where I: Iterator, I::Item: Clone, { type Item = Vec; fn next(&mut self) -> Option { let Self { vals, state } = self; match state { PermutationState::Start { k: 0 } => { *state = PermutationState::End; Some(Vec::new()) } &mut PermutationState::Start { k } => { vals.prefill(k); if vals.len() != k { *state = PermutationState::End; return None; } *state = PermutationState::Buffered { k, min_n: k }; Some(vals[0..k].to_vec()) } PermutationState::Buffered { ref k, min_n } => { if vals.get_next() { let item = (0..*k - 1) .chain(once(*min_n)) .map(|i| vals[i].clone()) .collect(); *min_n += 1; Some(item) } else { let n = *min_n; let prev_iteration_count = n - *k + 1; let mut indices: Vec<_> = (0..n).collect(); let mut cycles: Vec<_> = (n - k..n).rev().collect(); // Advance the state to the correct point. for _ in 0..prev_iteration_count { if advance(&mut indices, &mut cycles) { *state = PermutationState::End; return None; } } let item = indices[0..*k].iter().map(|&i| vals[i].clone()).collect(); *state = PermutationState::Loaded { indices, cycles }; Some(item) } } PermutationState::Loaded { indices, cycles } => { if advance(indices, cycles) { *state = PermutationState::End; return None; } let k = cycles.len(); Some(indices[0..k].iter().map(|&i| vals[i].clone()).collect()) } PermutationState::End => None, } } fn count(self) -> usize { let Self { vals, state } = self; let n = vals.count(); state.size_hint_for(n).1.unwrap() } fn size_hint(&self) -> SizeHint { let (mut low, mut upp) = self.vals.size_hint(); low = self.state.size_hint_for(low).0; upp = upp.and_then(|n| self.state.size_hint_for(n).1); (low, upp) } } impl FusedIterator for Permutations where I: Iterator, I::Item: Clone, { } fn advance(indices: &mut [usize], cycles: &mut [usize]) -> bool { let n = indices.len(); let k = cycles.len(); // NOTE: if `cycles` are only zeros, then we reached the last permutation. for i in (0..k).rev() { if cycles[i] == 0 { cycles[i] = n - i - 1; indices[i..].rotate_left(1); } else { let swap_index = n - cycles[i]; indices.swap(i, swap_index); cycles[i] -= 1; return false; } } true } impl PermutationState { fn size_hint_for(&self, n: usize) -> SizeHint { // At the beginning, there are `n!/(n-k)!` items to come. let at_start = |n, k| { debug_assert!(n >= k); let total = (n - k + 1..=n).try_fold(1usize, |acc, i| acc.checked_mul(i)); (total.unwrap_or(usize::MAX), total) }; match *self { Self::Start { k } if n < k => (0, Some(0)), Self::Start { k } => at_start(n, k), Self::Buffered { k, min_n } => { // Same as `Start` minus the previously generated items. size_hint::sub_scalar(at_start(n, k), min_n - k + 1) } Self::Loaded { ref indices, ref cycles, } => { let count = cycles.iter().enumerate().try_fold(0usize, |acc, (i, &c)| { acc.checked_mul(indices.len() - i) .and_then(|count| count.checked_add(c)) }); (count.unwrap_or(usize::MAX), count) } Self::End => (0, Some(0)), } } }