Skip to content

Commit 83deca8

Browse files
ga63citphimuemue
ga63cit
authored andcommitted
initial commit implementing functionality of iterating over all partitions of a vector
1 parent a447b68 commit 83deca8

File tree

2 files changed

+75
-0
lines changed

2 files changed

+75
-0
lines changed

src/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -210,6 +210,7 @@ mod minmax;
210210
#[cfg(feature = "use_alloc")]
211211
mod multipeek_impl;
212212
mod pad_tail;
213+
mod partitions;
213214
#[cfg(feature = "use_alloc")]
214215
mod peek_nth;
215216
mod peeking_take_while;

src/partitions.rs

+74
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
/// Based on https://stackoverflow.com/a/30898130/4322240.
2+
3+
/// Representation of a state in which the iterator can be.
4+
/// elements: contains the elements to be partitioned. All elements are treated
5+
/// as distinct.
6+
/// index_map: in terms of the linked post, index_map[i] = p_i (but 0-indexed)
7+
/// is the partition class to which elements[i] belongs in the current
8+
/// partition
9+
/// initialized: marks if the Partition element was just initialized and hence
10+
/// was not generated by next()
11+
pub struct Partition<'a, T> where T: Copy {
12+
elements: &'a Vec<T>,
13+
index_map: Vec<usize>,
14+
initialized: bool,
15+
}
16+
17+
type PartitionRepresentation<T> = Vec<Vec<T>>;
18+
19+
20+
impl<'a, T> Partition<'a, T> where T: Copy {
21+
// extracts the current partition of the iterator
22+
fn create_partition(&self) -> PartitionRepresentation<T> {
23+
// max_index is the highest number used for a class in the partition.
24+
// Since the first class is numbered 0, there are max_index + 1 different classes.
25+
if let Some(&max_index) = self.index_map.iter().max() {
26+
// initialize Vec's for the classes
27+
let mut partition_classes = vec![Vec::new(); max_index + 1];
28+
for i in 0..self.index_map.len() {
29+
// elements[i] belongs to the partition class index_map[i]
30+
partition_classes[self.index_map[i]].push(self.elements[i]);
31+
}
32+
return partition_classes;
33+
} else {
34+
// The index_map might have length 0, which means that there are no elements.
35+
// There is precisely one partition of the empty set, namely the partition with no classes.
36+
return Vec::new();
37+
}
38+
}
39+
}
40+
impl<'a, T> Iterator for Partition<'a, T> where T: Copy {
41+
type Item = PartitionRepresentation<T>;
42+
43+
fn next(&mut self) -> Option<Self::Item> {
44+
if self.initialized {
45+
self.initialized = false;
46+
return Some(self.create_partition());
47+
}
48+
// search for the highest index at which the index_map is incrementable (see the linked post)
49+
for index in (1..self.index_map.len()).rev() {
50+
if (0..index).any(|x| self.index_map[x] == self.index_map[index]) {
51+
// increment the incrementable index
52+
self.index_map[index] += 1;
53+
// set all following entries to the lexicographically smallest suffix that makes the
54+
// index_map viable (see linked post), i.e. to zero.
55+
for x in index + 1..self.index_map.len() {
56+
self.index_map[x] = 0;
57+
}
58+
return Some(self.create_partition());
59+
}
60+
}
61+
// if there is no incrementable index, we have enumerated the last possible partition.
62+
return None;
63+
}
64+
}
65+
/// Returns an Iterator over all partitions of the given Vec.
66+
/// Example usage:
67+
/// ```
68+
/// for partition in partitions(&vec![7,8,9]){
69+
/// println!("{:?}", partition);
70+
/// }
71+
/// ```
72+
pub fn partitions<'a, T>(v: &'a Vec<T>) -> Partition<'a, T> where T: Copy {
73+
Partition::<T> { elements: v, index_map: vec![0; v.len()], initialized: true }
74+
}

0 commit comments

Comments
 (0)