【问题标题】:How do I create an iterator for the inside of a nested loop in Java?如何为 Java 中的嵌套循环内部创建迭代器?
【发布时间】:2012-03-13 05:25:58
【问题描述】:

我可以编写一个嵌套循环来遍历嵌套数组的元素,for-each 优雅地隐藏了遍历嵌套数组每一层的细节:

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();
        }
    }
}

但是这种方法的问题是:

  1. 需要使用双重嵌套循环来遍历数据结构这一事实在这里非常明显。
  2. 我必须为需要调用内部元素的每个函数复制这个嵌套循环。
  3. 这打破了遍历结构的方法的封装。我可能会选择使用其他结构来实现嵌套数组,并且不想将嵌套迭代的每个副本都更改为所需的任何遍历方法。
  4. 嵌套的 for-each 循环的结构是由内而外的。 Iterator 应该在内部处理数据结构遍历,而不是在嵌套内部调用所需的函数,从而暴露遍历过程中遇到的每个条目。

那么...我该如何更改它以便实现一个可以调用的迭代器:

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.
}

这会将迭代如何完成的细节留给 Foo_Iterator 类。

我的问题是“我如何编写 Foo_Iterator,跟踪嵌套迭代器的状态? 我认为它看起来像下面这样,但我错过了跟踪状态的位。

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.
    }
}

关于如何以“优雅”的方式做到这一点有什么建议吗?

谢谢。

【问题讨论】:

    标签: java foreach iterator nested-loops


    【解决方案1】:

    不确定这是否更优雅,但您也可以使用迭代器来跟踪您的状态(例如使用 String):

    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
        }
    }
    

    我实际上不认为跟踪这两个索引有什么问题。

    当然,在你的代码中fi 应该是一个Iterable(大概是你的超类),它实例化了FooIterator,消费者永远不会看到它。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-10-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多