Iterator Intersperse with Another Iterator

I'm looking for an Iterator method that will intersperse an existing iterator, but with another iterator. For example, if I have 2 iterators that produce:

it1 => {1,2,3,4}
it2 => {6,7,8}

... then I'd like to produce: {1,6,7,8,2,6,7,8,3,6,7,8}.

In my actual code, I want to separate values in an iterator by n 0s, but I can do this easily enough with repeat_n from Itertools. Sometime with lazy eval and no memory allocations would be great :slight_smile:

I guess what I'm really asking is if there is anything out-of-the-box so I don't have to go with my poorly named iterator adaptor:

struct InterspersePaddingIterator<T, I> {
    base_iter: I,
    padding: T,
    pad_amt: usize,
    cur: usize
}

impl <T, I: Iterator<Item=T>> InterspersePaddingIterator<T, I> {
    pub fn new(base_iter: I, padding: T, pad_amt: usize) -> Self {
        InterspersePaddingIterator {
            base_iter,
            padding,
            pad_amt,
            cur: pad_amt
        }
    }
}

impl <T: Clone, I: Iterator<Item=T>> Iterator for InterspersePaddingIterator<T, I> {
    type Item = T;
    
    fn next(&mut self) -> Option<Self::Item> {
        if self.cur >= self.pad_amt {
            self.cur = 0;
            return self.base_iter.next();
        } else {
            self.cur += 1;
            return Some(self.padding.clone())
        }
    }
}

Something like this?

fn main() {
    let vals = vec![1, 2, 3, 4].into_iter();
    let padding = [7, 8, 9];

    let interleaved = vals.flat_map(
        |x| std::iter::once(x).chain(padding.iter().copied())
    );

    dbg!(interleaved.collect::<Vec<_>>());
}

https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=d7edeb2ae5adf3b584fbdb1b5bdbfc6c


If you want the first and last element to both come from the value iterator, it gets a little more complicated:

fn main() {
    let mut vals = vec![1, 2, 3, 4].into_iter();
    let padding = vec![7, 8, 9].into_iter();

    let interleaved = vals.next().into_iter().chain(
        vals.flat_map(
            |x| padding.clone().chain(std::iter::once(x))
        )
    );

    dbg!(interleaved.collect::<Vec<_>>());
}

https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=394a13f9a3fd82f2bb60ab2986f6b993

1 Like

The first one is what I'm looking for... thanks @2e71828 !

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.