7

I have a number of Rust iterators specified by user input that I would like to iterate through in lockstep.

This sounds like a job for something like Iterator::zip, except that I may need more than two iterators zipped together. I looked at itertools::multizip and itertools::izip, but those both require that the number of iterators to be zipped be known at compile time. For my task the number of iterators to be zipped together depends on user input, and thus cannot be known at compile time.

I was hoping for something like Python's zip function which takes an iterable of iterables. I imagine the function signature might look like:

fn manyzip<T>(iterators: Vec<T>) -> ManyZip<T>
where
    T: Iterator

How can I zip more than two iterators? only answers for the situation where the number of iterators is known at compile time.

I can solve my particular problem using indices and such, it just feels like there ought to be a better way.

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
Nick
  • 258
  • 1
  • 3
  • 7
  • 1
    Supposing `ManyZip` existed, how should it implement `Iterator` -- should it yield `T`s, or `Vec`s, or `impl Iterator`s? – trent Mar 22 '19 at 02:31
  • You may find [How do I efficiently iterate through a `Vec>` row by row?](https://stackoverflow.com/questions/54756166/how-do-i-efficiently-iterate-through-a-vecvect-row-by-row) helpful. – trent Mar 22 '19 at 02:32
  • *`iterators: Vec`* — you want to be able to only accept a vector of iterators that are all the **exact** same type? – Shepmaster Mar 22 '19 at 02:45
  • Taking a (possibly owned) iterator of iterators and having next() return an iterator would be nice, but I wasn't able to work out the types on a hypothetical function signature as I was writing the question. – Nick Mar 22 '19 at 05:14

1 Answers1

7

Implement your own iterator that iterates over the input iterators and collects them:

struct Multizip<T>(Vec<T>);

impl<T> Iterator for Multizip<T>
where
    T: Iterator,
{
    type Item = Vec<T::Item>;

    fn next(&mut self) -> Option<Self::Item> {
        self.0.iter_mut().map(Iterator::next).collect()
    }
}

fn main() {
    let mz = Multizip(vec![1..=2, 10..=20, 100..=200]);

    for v in mz {
        println!("{:?}", v);
    }
}
Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
  • This assumes the iterators return same type of Items for each iterator. Is it possible to do the same but with potentially different types? – Anatoly Bugakov Sep 19 '22 at 17:02
  • @AnatolyBugakov no. Iterators _always_ return one and exactly one type. You could introduce an enum (or use an existing one like [either](https://docs.rs/either/)) and then you return one type with multiple possible variants. – Shepmaster Sep 19 '22 at 17:07