[英]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 參數。
您發布的代碼也不會編譯,原因如下:
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());
}
}
但我的建議是更注重效率和簡單性而不是簡潔性。 因為迭代器產生的所有值都可以很容易地即時計算,因此無需提前分配它們來占用內存。
相反,您可以維護兩個變量curX
和curY
。 此解決方案很簡單,並且還可以更好地控制您的迭代器,因為您沒有委托迭代過程。 因此,您可以實現一個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.