Search code examples
rustcombinatoricscartesian-productvariadicrust-itertools

Cartesian product of n ranges


I am rewriting a python program into rust and I am struggling to translate this line:

itertools.product(range(0,8), repeat=n)

What I am trying to achieve is something like this: https://pastebin.com/ceEA5E3q (but so that I can change the number of digits).

The yielded collections don't have to be tuples (or, even, they preferably shouldn't be tuples)

I tried writing a macro that would yield these iterators, since they work:

2 => iproduct!(0..8, 0..8)

3 => iproduct!(0..8, 0..8, 0..8)

4 => iproduct!(0..8, 0..8, 0..8, 0..8)

etc.

However, after a while I failed to create such macro.

I came up with this weird hack:

steps = 3;
for idx in 0..8_u128.pow(steps as u32) {
    let moves: Vec<u8> = format!("{:0fill$o}", idx, fill = steps)
        .chars()
        .map(|d| d.to_digit(10).unwrap() as u8)
        .collect();
    println!("{:?}", moves);
}

I am creating a string that contains a zero-filled octal number, then iterate over digits and convert them into a Vec of numbers. While it works, I feel like doing all of these operations, especially with strings, affects my performance negatively.


Solution

  • I think you can use Itertools::multi_cartesian_product:

    std::iter::repeat(0..8).take(n).multi_cartesian_product()
    

    or

    (0..n).map(|_| 0..8).multi_cartesian_product()