Goal: Create a function that returns an iterator for all combinations according to nCr.
For example, let n = 5 and let c = 3. The iterator should yield slices containing the following data.
0 1 2
0 1 3
0 1 4
0 2 3
0 2 4
0 3 4
1 2 3
1 2 4
1 3 4
To challenge myself, as I'm new to rust, I want to do it without allocating a new vector for every iteration. Instead, the iterator should modify a vector that it owns and always return a slice over the same vector. Yes, I know the values in the slice will change if the slice is improperly used after subsequent calls to next on the iterator.
/// Usage:
/// Let's find all factors of 100. We have obtained all the prime factors earlier.
/// ```
/// let prime_factors = vec![2, 2, 5, 5]; // obtained earlier
/// let mut all_factors = new HashMap::<usize>();
/// all_factors.insert(1);
///
/// // now use every combination of prime factors to find all the factors
/// for c in 1..=prime_factors.len() {
/// for indexes in combinations(prime_factors.len(), c) {
/// let mut factor = 1;
/// for index in indexes {
/// factor *= prime_factors[index];
/// }
/// all_factors.insert(factor);
/// }
/// }
///
/// // all_factors now contains [1, 2, 4, 5, 10, 20, 50, 100]
/// ````
fn combinations<'a>(n: usize, c: usize) -> impl Iterator<Item = &'a [usize]> {
struct State<'a> {
n: usize,
c: usize,
indexes: Vec<usize>, // I think State should OWN this vector
phantom: PhantomData<&'a ()>, // But I needed a field with a lifetime
}
impl<'a> State<'a> {
fn new(n: usize, c: usize) -> State<'a> {
State {
n,
c,
indexes: (0..c).collect::<Vec<usize>>(),
phantom: PhantomData,
}
}
fn update(&mut self) -> bool {
fn update(indexes: &mut Vec<usize>, at: usize, max: usize) -> bool {
indexes[at] += 1;
if indexes[at] == max {
if at == 0 {
return false;
}
if !update(indexes, at - 1, max - 1) {
return false;
}
indexes[at] = indexes[at - 1] + 1;
}
true
}
update(&mut self.indexes, self.c - 1, self.c)
}
}
impl<'a> Iterator for State<'a> {
type Item = &'a [usize];
fn next(self: &mut State<'a>) -> Option<&'a [usize]> {
if self.update() {
Some(&self.indexes[..])
} else {
None
}
}
}
State::new(n, c)
}