Iterate over two iterators, repeating elements from one of them based on a condition

I have two iterators that I want to iterate over together, but instead of advancing them both in lockstep I want to reuse the same element from one iterator when I advance the other one based on a condition. Here's some example code that hopefully makes my problem clear.

struct MyStruct {
    items: Vec<Item>,
}

struct Item {
    index: u32,
    value: String,
}

fn main() {
    let main_iter = (0..12).into_iter();
    let my_struct = MyStruct {
        items: vec![
            Item {
                index: 0,
                value: "a".to_string(),
            },
            Item {
                index: 3,
                value: "b".to_string(),
            },
            Item {
                index: 5,
                value: "c".to_string(),
            },
            Item {
                index: 8,
                value: "d".to_string(),
            },
        ],
    };

    let mut my_items_iter = my_struct.items.into_iter().peekable();
    let new_iter = main_iter.map(move |i| {
        let item = if i <= my_items_iter.peek().unwrap().index {
            // Here I want to return the current value of the iterator
            my_items_iter.peek().unwrap()
        } else {
            // Here I want to get the next value
            my_items_iter.next();
            my_items_iter.peek().unwrap()
        };
        some_function(i, &item.value)
    });

    // In my real code the iterator is run on another thread
    let handle = std::thread::spawn(move || {
        new_iter.for_each(|i| println!("{}", i));
    });
    handle.join().unwrap();
}

fn some_function(int: u32, string: &String) -> String {
    format!("{}: {}", int, string)
}

What I'm trying to do here is align the items from both iterators based on a index value by only advancing 'my_items_iter` if the current item does not have a matching index. The desired output is

0: a
1: a
2: a
3: b
4: b
5: c
6: c
7: c
8: d
9: d
10: d
11: d

This almost works but the items from the second iterator are slightly off and I get output

0: a
1: b
2: b
3: b
4: c
5: c
6: d
7: d
8: d

and then the thread panics because my_items_iter ran out of items.

I tried various other ways of checking the condition but I can't figure out how to solve this. I also had a look at the peekmore crate which has a PeekMoreIterator that allows you to peak ahead more than one item but I'm not convinced I even need that here.

Any pointers in the right direction would be very welcome.

Here's a minimal solution using some mutable state; I'll try to adapt it to a proper iterator.

Edit: here's the same code wrapped in an Iterator-implementing type.

1 Like

Here's another take.

1 Like

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.