簡體   English   中英

如何實現一個等效於 Java 中的嵌套循環的迭代器

[英]How to implement an Iterator that will be an equivalent of a nested loop in Java

我在Python中有以下生成器:

    def iterator(min,max,step,min2,max2,step2):
        for x in range(min,max,step):
            for y in range(min2, max2, step2):
                result = foo(x, y)
                yield result

我想用Java實現一個Iterator ,它的行為有點像以前的生成器。 我嘗試使用兩個內部迭代器,但它不起作用。

我該如何解決?

    public class Generator implements Iterator<Integer> {    
        private Iterator<Integer> xIterator;
        private Iterator<Integer> yIterator;    
    
        public Generator(int max1, int max2, int min1, int min2, int step1, int step2) {    
            xIterator = range(min1, max1, step1).iterator();
            yIterator = range(min2, max2, step2).iterator();    
        }
    
        @Override
        public Integer next() {
            while (xIterator.hasNext()) {
                xval = xIterator.next()
                while(yIterator.hasNext()) {
                    yval = yIterator.next()
                    return foo(xval, yval)
                }
            }
        }    
    
        public static int[] range(int min, int max, int step) {
            return IntStream.range(min, max / step + 1).map(x -> x * step).toArray();
        }    
    }

在 Python 中,在 yield 語句之后,對 Generator 的下一次調用會在該 yield 語句之后繼續 - 它位於內部循環中。

在 Java 中,在返回之后,對 next() 的下一次調用將在 while 循環之外繼續,所以它做的第一件事總是檢查 xIterator.hasNext(),如果這是真的,則增加 xval。 我認為這可能是主要的誤解。

范圍函數似乎也沒有做它應該做的事情。 也許檢查Java: Equivalent of Python's range(int, int)? - 那里的一些答案也包括 step 參數。

您發布的代碼也不會編譯,原因如下:

  • next() 並不總是返回一個值。 如果不存在(更多)元素,它應該拋出 NoSuchElementException。
  • hasNext() 沒有實現,使用這種方法實際上可能非常困難。
  • xval 和 yval 未聲明。

Java 中的Iterator是一個特殊的對象,是一種迭代的意思,它允許從特定的源一個接一個地順序檢索元素。

在創建自定義迭代器時必須實現兩種方法: hasNext() (如果存在下一個元素,則返回true )和next() (檢索下一個元素)。

您沒有為您的類提供hasNext()的實現,否則您的代碼將無法編譯。

而且next()方法有一個邏輯缺陷,它不會編譯,因為你沒有提供 return 語句或 throws 子句,當控件無法進入循環時將被執行。 但更重要的是,此方法中不需要循環和任何條件邏輯,它必須由hasNext()覆蓋,通常必須在next()之前調用。 如果客戶端代碼不尊重它,方法next()可能會產生異常。 您可以在next()方法的最開始添加if (hasNext())以使用您的自定義消息發出特定異常。

方法iterator()可通過數組訪問。 您可以將它與實現Iterable接口的類一起使用,例如集合,也可以在流上調用iterator() 所以你可以像這樣重新實現你的方法range()

IntStream.iterate(min, i -> i < max, i -> i + step).iterator();

這就是修復迭代器的方法:

public class Generator implements Iterator<Integer> {    
    private final Iterator<Integer> xIterator;
    private final Iterator<Integer> yIterator;
    
    public Generator(int minX, int minY, int maxX, int maxY, int stepX, int stepY) {
        this.xIterator = range(minX, maxX, stepX);
        this.yIterator = range(minY, maxY, stepY);
    }
    
    public static Iterator<Integer> range(int min, int max, int step) {
        return IntStream.iterate(min, i -> i < max, i -> i + step).iterator();
    }
    
    @Override
    public boolean hasNext() {
        return xIterator.hasNext() && yIterator.hasNext();
    }
    
    @Override
    public Integer next() {
        return foo(xIterator.next(), yIterator.next());
    }
}

但我的建議是更注重效率和簡單性而不是簡潔性。 因為迭代器產生的所有值都可以很容易地即時計算,因此無需提前分配它們來占用內存。

相反,您可以維護兩個變量curXcurY 此解決方案很簡單,並且還可以更好地控制您的迭代器,因為您沒有委托迭代過程。 因此,您可以實現一個reset()功能(這在以前的解決方案中是不可能的,當Iterator到達數據源的末尾時它變得無用)。

public class Generator implements Iterator<Integer> {
    private final int minX;
    private final int minY;
    private final int maxX;
    private final int maxY;
    private final int stepX;
    private final int stepY;
    
    private int curX;
    private int curY;
    
    public Generator(int minX, int minY, int maxX, int maxY, int stepX, int stepY) {
        this.minX = minX;
        this.minY = minY;
        this.maxX = maxX;
        this.maxY = maxY;
        this.stepX = stepX;
        this.stepY = stepY;
        this.curX = minX;
        this.curY = minY;
    }
    
    @Override
    public boolean hasNext() {
        return curX < maxX && curY < maxY;
    }
    
    @Override
    public Integer next() {
        int result = foo(curX, curY);
        curX += stepX;
        curY += stepY;
        return result;
    }
    
    public void reset() { // reset the iterator to the initial coordinates
        this.curX = minX;
        this.curY = minY;
    }
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM