Reputation: 69
I have 2 Vec
s:
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?
Upvotes: 4
Views: 8244
Reputation: 2654
The existing answers make sense if your goal is to get the Cartesian product of two iterators. If you've got vectors or slices already though (like in the original question) you can do a little better:
fn main() {
let x = vec!['1', '2', '3'];
let y = vec!['a', 'b', 'c'];
let result: Vec<String> = product(&x, &y)
.map(|(a, b)| format!("{}{}", a, b))
.collect();
println!("{:?}", result)
}
fn product<'a: 'c, 'b: 'c, 'c, T>(
xs: &'a [T],
ys: &'b [T],
) -> impl Iterator<Item = (&'a T, &'b T)> + 'c {
xs.iter().flat_map(move |x| std::iter::repeat(x).zip(ys))
}
Any iterator based solution will necessarily require storing the full contents of the iterator somewhere, but if you already have the data in a vector or array you can use the known size to only store the indices instead.
Upvotes: 6
Reputation: 2592
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);
}
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 String
s. 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
Upvotes: 7
Reputation: 42796
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);
}
Upvotes: 14