I have two Vec
s that can be of different lengths, for example:
let xs = vec![1, 2, 3, 4, 5];
let ys = vec![11, 12, 13];
I want to iterate over them in pairs, printing:
x=1, y=11
x=2, y=12
x=3, y=13
x=4; no matching Y
x=5; no matching Y
I can use Iterator::zip
to get the pairs with matching elements in both xs
and ys
:
for (x, y) in xs.iter().zip(ys.iter()) {
println!("x={}, y={}", x, y);
}
but for the "no matching" bits I need complex code that checks the length and takes a slice of the rest.
I wanted a solution that's fully iterator-based, so I tried:
let mut it_xs = xs.iter();
let mut it_ys = ys.iter();
while let (Some(x), Some(y)) = (it_xs.next(), it_ys.next()) {
println!("x={}, y={}", x, y);
}
while let Some(x) = it_xs.next() {
println!("x={}, no matching Y", x);
}
while let Some(y) = it_ys.next() {
println!("y={}, no matching X", y);
}
which does not work correctly, as the first loop skips the first element that doesn't have a match in the other list (x=4).
Is it possible to solve with the help of an iterator without slicing the rest of the larger Vec
?
The implementation without external crates:
let mut it_xs = xs.iter();
let mut it_ys = ys.iter();
loop {
match (it_xs.next(), it_ys.next()) {
(Some(x), Some(y)) => println!("x={}, y={}", x, y),
(Some(x), None) => println!("x={}, no matching Y", x),
(None, Some(y)) => println!("y={}, no matching X", y),
(None, None) => break,
}
}
itertools
has a method zip_longest
that does just that:
use itertools::Itertools;
use itertools::EitherOrBoth::{Both, Left, Right};
for it in xs.iter().zip_longest(ys.iter()) {
match it {
Both(x, y) => println!("x={}, y={}", x, y),
Left(x) => println!("x={}, no matching Y", x),
Right(y) => println!("y={}, no matching X", y),
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With