I've been looking at some of my past code and recently rediscovered this:
// Enumerate all permutations with repetitions and for all output lengths from 1 to `max_len`.
// Don't ask me how this works, I typed it out in a single stream of consciousness.
fn perms_iter<'a, T: Copy>(
input: &'a [T],
max_len: u32,
) -> impl Iterator<Item = impl Iterator<Item = T> + 'a> {
(1..=max_len)
.flat_map(move |len| (0..input.len().pow(len)).zip(std::iter::repeat(len)))
.map(move |(mut n, j)| {
(0..j).map(move |_| {
let s = input[n % input.len()];
n /= input.len();
s
})
})
}
I need something similar now but past me's comment isn't very encouraging. Can this be done better?
EDIT: It's used like this:
for perm in perms_iter(&['a', 'b', 'c'], 4) {
for c in perm {
print!("{}", c);
}
println!("");
}
I guess, changing pow to checked_pow+unwrap could be an improvement, if you’re planning on ever risking an overflow, otherwise some items very late in the iterator may be messed up on 32bit platforms in release mode.
I would probably try to write it using arrays to avoid the allocations and generate the iterator with a macro to avoid integer division. (but a branch misprediction is probably more costly .. so yours might still be faster).
Not really the same, that one’s producing Vectors. And it’s actually doing only permutations, whereas the one here is more of a cartesian products thing.
Well I was looking to generate an exhaustive (up to n chars) test of a simple parser and this looked like it might do the job but the comment I left myself had me worried (but maybe I was just feeling unhelpful that day).
I would like something that I can plug right into rayon but if the code is basically ok then I can adapt it.