/// 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"] pubstruct Permutations<I: Iterator> {
vals: LazyBuffer<I>,
state: PermutationState,
}
impl<I> Clone for Permutations<I> 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: Box<[usize]>,
cycles: Box<[usize]>,
}, /// No permutation left to generate.
End,
}
impl<I> fmt::Debug for Permutations<I> where
I: Iterator + fmt::Debug,
I::Item: fmt::Debug,
{
debug_fmt_fields!(Permutations, vals, state);
}
pubfn permutations<I: Iterator>(iter: I, k: usize) -> Permutations<I> {
Permutations {
vals: LazyBuffer::new(iter),
state: PermutationState::Start { k },
}
}
impl<I> Iterator for Permutations<I> where
I: Iterator,
I::Item: Clone,
{ type Item = Vec<I::Item>;
fn next(&mutself) -> Option<Self::Item> { letSelf { 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; letmut indices: Box<[_]> = (0..n).collect(); letmut cycles: Box<[_]> = (n - k..n).rev().collect(); // Advance the state to the correct point. for _ in0..prev_iteration_count { if advance(&mut indices, &mut cycles) {
*state = PermutationState::End; return None;
}
} let item = vals.get_at(&indices[0..*k]);
*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(vals.get_at(&indices[0..k]))
}
PermutationState::End => None,
}
}
fn count(self) -> usize { letSelf { vals, state } = self; let n = vals.count();
state.size_hint_for(n).1.unwrap()
}
impl<I> FusedIterator for Permutations<I> 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; returnfalse;
}
} 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)),
}
}
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.