I have to implement an Iterator<E> that needs to internally iterate through multiple private iterators at different levels. For example, an Iterator<A>, an Iterator<B>, and an Iterator<C>. The Iterator<A> exists for the life of my Iterator, but the Iterator<B> and Iterator<C> instances are made from the current values for A and B, respectively.

At any given iteration, the Iterator<C> might be exhausted and so I'll have to advance to the next() of Iterator<B>, from which I will establish a new Iterator<C>. I hope this is clear.

My question is: is there any better structure than this (below)? My real case has 5-6 levels of nested iterators and I'm finding this ugly and unsatisfying.

if ( this.cIterator == null || ! this.cIterator.hasNext() ) {
    // We do not have a C iterator established, or the one we had established is exhausted
    // We need a new one, which will come from the next B
    if ( this.bIterator = null || !this.bIterator.hasNext() ) {
        // We do not have a B iterator established or the one we had is exhausted.
        // We need a new one, which will come from the next A
        if ( this.aIterator == null || !this.aIterator.hasNext() ) {
            // Our aIterator is non-existent or exhausted.  We are done.
            throw new NoSuchElementException();
    }
        // At this point, we can move on to the next A.
        this.currentA = this.aIterator.next();
        this.bIterator = this.currentA.getIteratorSourceCollection().iterator();
        // assert this.bIterator.hasNext(); // will be true in my case
    }
    // At this point, we are guaranteed to have a B iterator with at least one element left
    this.currentB = bIterator.next();
    this.cIterator = this.currentB.getIteratorSourceCollection().iterator();
    // assert this.cIterator.hasNext();  // will be true in my case
}
// At this point, we are guaranteed to have a C iterator with a next element.
return new E(this.currentA, this.currentB, this.cIterator.next());
             

4 Replies 4

I wonder whether this is really an occasion to use iterators at all, given the requirements to refresh those for B and C.

I am using a 3rd party library that requires an Iterator. It is important for performance that I be honest about the Iterator implementation rather than, say, pre-creating all the entries, storing them in a collection, and then just returning an iterator on that collection.

Your approach looks entirely reasonable, but you might implement a more general iterator-of-iterators that does one level of nesting, perhaps with a Function<A, Iterator<B>>, and then use it several levels deeply. You might profitably look at operators like Guava's Iterators.concat(Iterator<Iterator<T>>).

Another option could be to use streams as intermediate:

Spliterator<A> spliteratorA = Spliterators.spliteratorUnknownSize(iteratorA, 0);
Iterator<E> iterator = StreamSupport.stream(spliteratorA, false)
        .flatMap(a -> {
            Iterator<B> iteratorB = a.getIteratorSourceCollection().iterator();
            Spliterator<B> spliteratorB = Spliterators.spliteratorUnknownSize(iteratorB, 0);
            return StreamSupport.stream(spliteratorB, false)
                    .flatMap(b -> {
                        Iterator<C> iteratorC = b.getIteratorSourceCollection().iterator();
                        Spliterator<C> spliteratorC = Spliterators.spliteratorUnknownSize(iteratorC, 0);
                        return StreamSupport.stream(spliteratorC, false)
                                .map(c -> new E(a, b, c));
                    });
        })
        .iterator();

By adding a utility method for the conversion of iterator to stream you can simplify it a bit.

As for performance, the returned iterator is just as lazy as its backing stream.

Your Reply

By clicking “Post Your Reply”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.