简体   繁体   中英

How do I create an iterator for the inside of a nested loop in Java?

I can write a nested loop to iterate over the elements of a nested array, the for-each elegantly hides the details of the traversal over each level of the nested array:

Foo[][] dbl_array;
public void do_all() {
    // Iterate over both levels of a nested array, invoking "bar" on each inner element.
    for (final Foo[] arr_1d : dbl_array) {
        for (final Foo el : arr_1d) {
            el.bar();
        }
    }
}

But the problems with this approach are:

  1. The fact that a doubly-nested loop is needed to traverse the data structure is painfully obvious here.
  2. I have to copy this nested loop for every function I need to call on the inner elements.
  3. This breaks the encapsulation of the method for traversing the structure. I may choose to implement the nested array with some other structure and don't want to change every copy of the nested iterations to whatever traversal method is needed.
  4. The structure of the nested for-each loops is inside out from what is needed. Instead of having the desired function call inside the nests, an Iterator should handle the data structure traversal internally, exposing each entry encountered during the traversal.

So...how do I change this so that I implement an Iterator that I could invoke like:

Foo_Iterator fi = Foo.iterator();
for (final Foo el : fi) { // The Iterator hides the traversal details from the caller.
    el.bar();             // The desired function is invoked on each element encountered.
}

This would leave the details of how the iteration is done to the Foo_Iterator class.

My question is "How do I write Foo_Iterator, keeping track of the state of the nested iterators? I think it would look something like the following, but I'm missing the bits that keep track of the state.

class Foo_Iterator extends Whiz implements Iterator {
    public Foo_Iterator() {
        // Initialize state based on access to the superclass Whiz.
    }
    public boolean hasNext() {
        // Is there an elegant way to save the state of both iterators between each call to hasNext() and next()?
        // The "inelegant" way would be to keep track of the inner and out array indices,
        // comparing the current index to the array length...
    }
    public Foo next() {
        // Access the "next" in the nested sequence.
    }
    public void remove() {
        // I probably won't implement or need/use this one.
    }
}

Any suggestions on how to do this the "elegant" way?

Thanks.

Not sure if this is any more elegant, but you can use iterators too keep track of the state for you (using String for example purposes):

class FooIterator implements Iterator<String> {

    private final Iterator<String[]> outer;
    private Iterator<String> inner = null;

    public FooIterator(String[][] data) {
        outer = Arrays.asList(data).iterator();
        nextInner();
    }

    private void nextInner() {
        if (outer.hasNext())
            inner = Arrays.asList(outer.next()).iterator();
    }

    public boolean hasNext() {
        return inner != null && inner.hasNext();
    }

    public String next() {
        String next = inner.next();
        if (!inner.hasNext())
            nextInner();
        return next;
    }

    public void remove() {
        // not used
    }
}

I actually don't think there's anything wrong with keeping track of the two indices.

Of course, in your code fi should really be an Iterable (presumably your super class), which instantiates FooIterator , which the consumers should never see.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM