当前位置: 首页 > 知识库问答 >
问题:

如何实现一个迭代器,它将是Java中嵌套循环的等价物

晏弘雅
2023-03-14

我有以下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中实现一个迭代器,它的行为有点像之前的生成器。我曾尝试使用两个内部迭代器,但它不起作用。

我该怎么修?

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

共有2个答案

隗和裕
2023-03-14

Java中的Iterator是一个特殊的对象,是迭代的平均值,它允许从特定的源按顺序一个接一个地检索元素。

创建自定义迭代器时必须实现两种方法:hasNext()(如果存在下一个元素,则返回true)和next()(检索下一个元素)。

您没有为您的类提供hasNext()的实现,否则您的代码将无法编译。

next()方法中有一个逻辑缺陷,它将无法编译,因为您没有提供返回语句或抛出子句,当控件无法进入循环时,这些语句或子句将被执行。但更重要的是,在这个方法中不需要循环和任何条件逻辑,它必须被hasNext()覆盖,通常必须在next()之前调用。如果客户端代码不尊重它,方法next()可能会产生异常。您可以在next()方法的开头添加if(hasNext()),以对自定义消息发出特定异常。

methoditerator()可通过数组访问。您可以将其与实现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;
    }
}
顾喜
2023-03-14

在Python中,在一条yield语句之后,对生成器的下一次调用将在该yield语句之后继续进行,该语句位于内部循环中。

在Java中,在返回之后,对next()的下一次调用将在while循环之外继续,因此它所做的第一件事总是检查xIterator。hasNext(),如果这是真的,则递增xval。我认为这可能是主要的误解。

而且,范围函数似乎没有完成它应该做的事情。也许可以看看Java:相当于Python的范围(int,int)?-其中一些答案还包括step论证。

您发布的代码也不会编译,原因如下:

  • next()并不总是返回值。如果不存在(更多)元素,它应该抛出NosTouchElementException
 类似资料:
  • 我有以下python生成器: 而且我想在Java中实现一个迭代器,它的行为有点像以前的生成器。我试图使用两个内部迭代器,但它不起作用。想法?

  • 问题内容: 我有一个像这样的嵌套循环构造: 现在如何摆脱两个循环?我看过类似的问题,但没有一个是Java特有的。我无法应用这些解决方案,因为大多数使用的gotos。 我不想将内部循环使用其他方法。 我不想重新运行循环。中断时,我完成了循环块的执行。 问题答案: 像其他答复者一样,我绝对希望将循环放入另一种方法中,此时你可以返回以完全停止迭代。该答案仅显示了如何满足问题中的要求。 你可以将break

  • 为了在运行性能脚本之前用大量数据填充系统,我们理想的用例是使用Gatling。数据不需要不同,除了具有唯一的主ID。 上面的示例可以通过更改的值来创建任意数量的对象,但是在大范围(例如100000个对象)下,线性地这样做变得不切实际。所以我想做的是有一个共享的对象池,由100个用户创建。 当然,这就是喂食器的使用案例。而不是生成一个静态的或使用使用简单的迭代循环(例如到)似乎最简单。 我知道(从文

  • 您认为这样的迭代器嵌套是好还是坏? 上下文:for循环版本中断,因为我在for循环中使用同义词的同时附加同义词。 或者,在for循环版本中,我可以复制HashMap 非常感谢。 下面是一个更好的例子。 目前正在考虑使用HashMap.size()用for循环替换第一个itr,这样当我稍后追加HashMap时就不会中断。 非常感谢。

  • 问题内容: 考虑以下代码: 我有一些要求,例如我想读取/获取所有类型的键和值以进行某些处理,但我无法定义它,因为我将获得动态JSON输入(例如,作为字符串,那么第二级循环将给我索引)数组并处理每个具有key 和的JSON 。 我希望遍历其中包含的每个键/值对,浏览地图的最有效方法是什么? 注意:我是Go-lang的新手,也欢迎您提出问题。 问题答案: 请参阅此博客条目,该条目彻底涵盖了该主题,尤其

  • 问题内容: 我已经使用Java已有一段时间了,但是我对循环的教育还是有点不足。我知道如何创建存在于Java中的每个循环以及如何打破循环。但是,最近我想到了: 假设我有两个嵌套循环。我可以只使用一条语句来打破两个循环吗? 这是我到目前为止所拥有的。 有没有办法做到这一点? 问题答案: 在Java中,您可以使用标签来指定要中断/继续的循环: