| use alloc::vec::Vec; | |
| use std::fmt; | |
| use std::iter::FusedIterator; | |
| 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<I: Iterator> { | |
| combs: Combinations<I>, | |
| } | |
| impl<I> Clone for Powerset<I> | |
| where | |
| I: Clone + Iterator, | |
| I::Item: Clone, | |
| { | |
| clone_fields!(combs); | |
| } | |
| impl<I> fmt::Debug for Powerset<I> | |
| 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<I>(src: I) -> Powerset<I> | |
| where | |
| I: Iterator, | |
| I::Item: Clone, | |
| { | |
| Powerset { | |
| combs: combinations(src, 0), | |
| } | |
| } | |
| impl<I: Iterator> Powerset<I> { | |
| /// Returns true if `k` has been incremented, false otherwise. | |
| fn increment_k(&mut self) -> bool { | |
| if self.combs.k() < self.combs.n() || self.combs.k() == 0 { | |
| self.combs.reset(self.combs.k() + 1); | |
| true | |
| } else { | |
| false | |
| } | |
| } | |
| } | |
| impl<I> Iterator for Powerset<I> | |
| where | |
| I: Iterator, | |
| I::Item: Clone, | |
| { | |
| type Item = Vec<I::Item>; | |
| fn next(&mut self) -> Option<Self::Item> { | |
| if let Some(elt) = self.combs.next() { | |
| Some(elt) | |
| } else if self.increment_k() { | |
| self.combs.next() | |
| } else { | |
| None | |
| } | |
| } | |
| fn nth(&mut self, mut n: usize) -> Option<Self::Item> { | |
| loop { | |
| match self.combs.try_nth(n) { | |
| Ok(item) => return Some(item), | |
| Err(steps) => { | |
| if !self.increment_k() { | |
| return None; | |
| } | |
| n -= steps; | |
| } | |
| } | |
| } | |
| } | |
| 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<B, F>(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<I> FusedIterator for Powerset<I> | |
| where | |
| I: Iterator, | |
| I::Item: Clone, | |
| { | |
| } | |
| fn remaining_for(n: usize, k: usize) -> Option<usize> { | |
| (k + 1..=n).try_fold(0usize, |sum, i| sum.checked_add(checked_binomial(n, i)?)) | |
| } |