Skip to content

Commit

Permalink
initial commit implementing functionality of iterating over all parti…
Browse files Browse the repository at this point in the history
…tions of a vector
  • Loading branch information
ga63cit authored and phimuemue committed Sep 26, 2024
1 parent a447b68 commit 83deca8
Show file tree
Hide file tree
Showing 2 changed files with 75 additions and 0 deletions.
1 change: 1 addition & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -210,6 +210,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;
Expand Down
74 changes: 74 additions & 0 deletions src/partitions.rs
Original file line number Diff line number Diff line change
@@ -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<T>,
index_map: Vec<usize>,
initialized: bool,
}

type PartitionRepresentation<T> = Vec<Vec<T>>;


impl<'a, T> Partition<'a, T> where T: Copy {
// extracts the current partition of the iterator
fn create_partition(&self) -> PartitionRepresentation<T> {
// 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<T>;

fn next(&mut self) -> Option<Self::Item> {
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<T>) -> Partition<'a, T> where T: Copy {
Partition::<T> { elements: v, index_map: vec![0; v.len()], initialized: true }
}

0 comments on commit 83deca8

Please sign in to comment.