rustiterator

How to iterate over two elements in a collection stepping by one using Iterator?


Suppose we have a vector:

let a = vec![1, 2, 3];

What is the best and shortest way to iterate over the elements so, that in the first iteration I receive a tuple of (1, 2), and in the next iteration - (2, 3), until there are no elements, so without producing the (3, None) or anything like that? It seems that a.chunks(2) is a bit different, it steps by two, while I need to step by one over every two consecutive elements in a collection.


Solution

  • There are multiple ways to do so.

    Given

    let a = vec![1, 2, 3];
    

    Using the standard library:

    .zip

    let result = a.iter()
        .zip(a.iter().skip(1))
        .inspect(|(a, b)| println!("a: {}, b: {}", a, b))
        .collect::<Vec<_>>();
    

    .windows

    let result = a.windows(2)
        .inspect(|w| println!("a: {}, b: {}", w[0], w[1]))
        .collect::<Vec<_>>();
    

    Worth noting, in case this matters, is that windows() iterates over subslices, so unlike the above method, collect() in this case will not give you a Vec of tuples.

    Using the Itertools crate:

    .tuple_windows

    use itertools::Itertools;
    
    let result = a.iter()
        .tuple_windows()
        .inspect(|(a, b)| println!("a: {}, b: {}", a, b))
        .collect::<Vec<_>>();
    

    All of the above methods will print the following:

    a: 1, b: 2
    a: 2, b: 3
    

    As a bonus, Itertools as of recent also has a .circular_tuple_windows(), which performs an extra iteration by including the last (3) and first (1) element:

    use itertools::Itertools;
    
    let result = a.iter()
        .circular_tuple_windows()
        .inspect(|(a, b)| println!("a: {}, b: {}", a, b))
        .collect::<Vec<_>>();
    
    a: 1, b: 2
    a: 2, b: 3
    a: 3, b: 1