Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Iterate two vectors with different lengths

Tags:

rust

I have two Vecs 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?

like image 511
user1244932 Avatar asked Nov 29 '22 23:11

user1244932


2 Answers

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,
    }
}
like image 151
aSpex Avatar answered Feb 23 '23 09:02

aSpex


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),
    }
}
like image 37
mcarton Avatar answered Feb 23 '23 07:02

mcarton