From e7ada660adfc18d6df0145668b6cad0b212f6366 Mon Sep 17 00:00:00 2001 From: ga63cit Date: Fri, 12 Aug 2022 15:34:35 +0200 Subject: [PATCH] initial commit implementing functionality of iterating over all partitions of a vector --- src/lib.rs | 1 + src/partitions.rs | 74 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 75 insertions(+) create mode 100644 src/partitions.rs diff --git a/src/lib.rs b/src/lib.rs index 5cca5d99f..ede7a6893 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -218,6 +218,7 @@ mod minmax; #[cfg(feature = "use_alloc")] mod multipeek_impl; mod pad_tail; +mod partitions; #[cfg(feature = "use_alloc")] mod peek_nth; mod peeking_take_while; diff --git a/src/partitions.rs b/src/partitions.rs new file mode 100644 index 000000000..55416ed23 --- /dev/null +++ b/src/partitions.rs @@ -0,0 +1,74 @@ +/// Based on https://stackoverflow.com/a/30898130/4322240. + +/// Representation of a state in which the iterator can be. +/// elements: contains the elements to be partitioned. All elements are treated +/// as distinct. +/// index_map: in terms of the linked post, index_map[i] = p_i (but 0-indexed) +/// is the partition class to which elements[i] belongs in the current +/// partition +/// initialized: marks if the Partition element was just initialized and hence +/// was not generated by next() +pub struct Partition<'a, T> where T: Copy { + elements: &'a Vec, + index_map: Vec, + initialized: bool, +} + +type PartitionRepresentation = Vec>; + + +impl<'a, T> Partition<'a, T> where T: Copy { + // extracts the current partition of the iterator + fn create_partition(&self) -> PartitionRepresentation { + // max_index is the highest number used for a class in the partition. + // Since the first class is numbered 0, there are max_index + 1 different classes. + if let Some(&max_index) = self.index_map.iter().max() { + // initialize Vec's for the classes + let mut partition_classes = vec![Vec::new(); max_index + 1]; + for i in 0..self.index_map.len() { + // elements[i] belongs to the partition class index_map[i] + partition_classes[self.index_map[i]].push(self.elements[i]); + } + return partition_classes; + } else { + // The index_map might have length 0, which means that there are no elements. + // There is precisely one partition of the empty set, namely the partition with no classes. + return Vec::new(); + } + } +} +impl<'a, T> Iterator for Partition<'a, T> where T: Copy { + type Item = PartitionRepresentation; + + fn next(&mut self) -> Option { + if self.initialized { + self.initialized = false; + return Some(self.create_partition()); + } + // search for the highest index at which the index_map is incrementable (see the linked post) + for index in (1..self.index_map.len()).rev() { + if (0..index).any(|x| self.index_map[x] == self.index_map[index]) { + // increment the incrementable index + self.index_map[index] += 1; + // set all following entries to the lexicographically smallest suffix that makes the + // index_map viable (see linked post), i.e. to zero. + for x in index + 1..self.index_map.len() { + self.index_map[x] = 0; + } + return Some(self.create_partition()); + } + } + // if there is no incrementable index, we have enumerated the last possible partition. + return None; + } +} +/// Returns an Iterator over all partitions of the given Vec. +/// Example usage: +/// ``` +/// for partition in partitions(&vec![7,8,9]){ +/// println!("{:?}", partition); +/// } +/// ``` +pub fn partitions<'a, T>(v: &'a Vec) -> Partition<'a, T> where T: Copy { + Partition:: { elements: v, index_map: vec![0; v.len()], initialized: true } +} \ No newline at end of file