use alloc::vec::Vec; use std::fmt; use std::iter::FusedIterator; use std::usize; use super::combinations::{combinations, Combinations}; use crate::adaptors::checked_binomial; use crate::size_hint::{self, SizeHint}; /// An iterator to iterate through the powerset of the elements from an iterator. /// /// See [`.powerset()`](crate::Itertools::powerset) for more /// information. #[must_use = "iterator adaptors are lazy and do nothing unless consumed"] pub struct Powerset { combs: Combinations, } impl Clone for Powerset where I: Clone + Iterator, I::Item: Clone, { clone_fields!(combs); } impl fmt::Debug for Powerset where I: Iterator + fmt::Debug, I::Item: fmt::Debug, { debug_fmt_fields!(Powerset, combs); } /// Create a new `Powerset` from a clonable iterator. pub fn powerset(src: I) -> Powerset where I: Iterator, I::Item: Clone, { Powerset { combs: combinations(src, 0), } } impl Iterator for Powerset where I: Iterator, I::Item: Clone, { type Item = Vec; fn next(&mut self) -> Option { if let Some(elt) = self.combs.next() { Some(elt) } else if self.combs.k() < self.combs.n() || self.combs.k() == 0 { self.combs.reset(self.combs.k() + 1); self.combs.next() } else { None } } fn size_hint(&self) -> SizeHint { let k = self.combs.k(); // Total bounds for source iterator. let (n_min, n_max) = self.combs.src().size_hint(); let low = remaining_for(n_min, k).unwrap_or(usize::MAX); let upp = n_max.and_then(|n| remaining_for(n, k)); size_hint::add(self.combs.size_hint(), (low, upp)) } fn count(self) -> usize { let k = self.combs.k(); let (n, combs_count) = self.combs.n_and_count(); combs_count + remaining_for(n, k).unwrap() } fn fold(self, mut init: B, mut f: F) -> B where F: FnMut(B, Self::Item) -> B, { let mut it = self.combs; if it.k() == 0 { init = it.by_ref().fold(init, &mut f); it.reset(1); } init = it.by_ref().fold(init, &mut f); // n is now known for sure because k >= 1 and all k-combinations have been generated. for k in it.k() + 1..=it.n() { it.reset(k); init = it.by_ref().fold(init, &mut f); } init } } impl FusedIterator for Powerset where I: Iterator, I::Item: Clone, { } fn remaining_for(n: usize, k: usize) -> Option { (k + 1..=n).try_fold(0usize, |sum, i| sum.checked_add(checked_binomial(n, i)?)) }