1

I created a small example that runs in the Rust Playground:

#[derive(Clone)]
pub struct Person {
    pub firstname: Vec<u8>,
    pub surname: Vec<u8>,
}

fn main() {
    let p0 = Person {
        firstname: vec![0u8; 5],
        surname: vec![1u8; 5],
    };
    let p1 = Person {
        firstname: vec![2u8; 7],
        surname: vec![3u8; 2],
    };
    let p2 = Person {
        firstname: vec![4u8; 8],
        surname: vec![5u8; 8],
    };
    let p3 = Person {
        firstname: vec![6u8; 3],
        surname: vec![7u8; 1],
    };

    let people = [p0, p1, p2, p3];

    for i in 0..people.len() {
        if i + 1 < people.len() {
            println!(
                "{:?}",
                (people[i].firstname.clone(), people[i + 1].surname.clone())
            )
        }
    }
}

Given the array people, I want to iterate its elements and collect tuples of the first name of the person at index i and the surname of the person at index i+1. This simple for loop does the job, but let's assume that instead of println I would like to pass such tuple into some function f. I can easily do this in this for loop, but I would like to learn whether I can implement that using an iterator iter() (and later apply collect() or fold functions if needed) instead of using the for loop?

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
Ziva
  • 3,181
  • 15
  • 48
  • 80

2 Answers2

2

You can combine two features:

  1. Create an array iterator that skips the first elements (iter().skip(1)).
  2. Iterator.zip
#[derive(Clone)]
pub struct Person {
    pub firstname: Vec<u8>,
    pub surname: Vec<u8>,
}

fn main() {
    let p0 = Person {
        firstname: vec![0u8; 5],
        surname: vec![1u8; 5],
    };
    let p1 = Person {
        firstname: vec![2u8; 7],
        surname: vec![3u8; 2],
    };
    let p2 = Person {
        firstname: vec![4u8; 8],
        surname: vec![5u8; 8],
    };
    let p3 = Person {
        firstname: vec![6u8; 3],
        surname: vec![7u8; 1],
    };

    let people = [p0, p1, p2, p3];

    for (i, j) in people.iter().zip(people.iter().skip(1)) {
        println!("{:?}", (&i.firstname, &j.surname));
    }
}

Permalink to the playground

Stargateur
  • 24,473
  • 8
  • 65
  • 91
mcarton
  • 27,633
  • 5
  • 85
  • 95
2

I would use slice::windows:

for window in people.windows(2) {
    println!("{:?}", (&window[0].firstname, &window[1].surname))
}

See also:

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
  • I would add https://docs.rs/itertools/0.8.2/itertools/trait.Itertools.html?search=#method.tuple_windows to the suggestion. – Stargateur Dec 09 '19 at 15:25
  • 1
    @Stargateur that's the "Are there equivalents..." question in the "see also" section. Since this case starts from an array/slice, I didn't feel like it needed to be directly mentioned. – Shepmaster Dec 09 '19 at 15:28