How do I get the cartesian product of 2 vectors by using Iterator?

Viewed 1345

I have 2 Vecs:

let x = vec!['1', '2', '3'];
let y = vec!['a', 'b', 'c'];

Now I want to use iterator to make a new vec like this ['1a', '1b', '1c', '2a', '2b', '2c', '3a', '3b', '3c']. How can I do?

2 Answers

Easiest way would be to use the cartesian product macro available in the itertools crate

use itertools::iproduct; // 0.10.1

fn main() {
    let x = vec!['1', '2', '3'];
    let y = vec!['a', 'b', 'c'];
    let product: Vec<String> = iproduct!(x, y)
        .map(|(a, b)| format!("{}{}", a, b))
        .collect();
    println!("{:?}", product);
}

Playground

Here is how to do it with vanilla Rust iterators:

fn main() {
    let x = vec!['1', '2', '3'];
    let y = vec!['a', 'b', 'c'];
    let product: Vec<String> = x
        .iter()
        .map(|&item_x| y
            .iter()
            .map(move |&item_y| [item_x, item_y]
                .iter()
                .collect()
                )
            )
        .flatten()
        .collect();
    
    println!("{:?}", product);
}

Explanation

The easiest way to construct a String from two chars is to collect iterator over the chars:

let string: String = [item_x, item_y].iter().collect();

For each item in x we iterate over y and construct such string.

x.iter().map(|&item_x| y.iter.map(move |&item_y| ...));

We use pattern matching to get value in the map closure rather then references. Because of that and the fact that the char has Copy trait, we can move item_x into inner closure, resolving any lifetime issues.

As the result of the code above we get an iterator over iterators over Strings. To flatten that iterator, we use flatten method (who would think?). Then we collect the flat iterator into the resulting Vec.

Playground: https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=bf2987ed96303a0db0f629884492011e

Related