【问题标题】:creating custom iterator with unit tests使用单元测试创​​建自定义迭代器
【发布时间】:2018-10-13 13:06:45
【问题描述】:

我正在学习编程并且是这个领域的新手,因为我有机械背景。 昨天我收到了教授的问题陈述。他为我们提供了一个自定义迭代器,旨在交替迭代给定的元素。

Alternate Iterator 代码如下。

import java.util.Iterator;

import java.util.LinkedList;

import java.util.Queue;

public class AlternatingIterator<E> implements Iterator{

private final Queue<E> queue = new LinkedList<>();

public AlternatingIterator(Iterator<E> ... iterators) {
    for(Iterator<E> iterator : iterators) {
        while(iterator.hasNext())
            queue.add(iterator.next());
    }
}

@Override
public boolean hasNext() {
    return queue.isEmpty() ? false : true;
}

@Override
public Object next() {
    return queue.poll();
}

}

现在,AlternatingIterator 应该在它在其构造函数中接收的迭代器之间按顺序交替。例如,如果使用三个迭代器 [a,b,c]、[1,2] 和 [x,y,z] 构造,则迭代器应按以下顺序生成元素 'a, 1, x, b, 2, y , c, z'

我还必须为“hasNext”和“next”方法编写单元测试。

我们可以实现除队列之外的任何其他数据结构吗?

我对如何解决这个挑战感到非常震惊和厌倦,但在这里却很困惑。如果你们可以帮助我,那么我可以很快学习重要的概念。

在此先感谢您的帮助。

【问题讨论】:

  • 通过将现有迭代器中的元素复制到集合中来实现迭代器是没有意义的:您也可以只使用该集合中的迭代器。我怀疑分配的重点是使用输入迭代器而不提前使用它们。
  • 什么是输入迭代器?
  • 输入迭代器是您提供给构造函数的迭代器:Iterator&lt;E&gt; ... iterators

标签: java junit collections iterator


【解决方案1】:

当然,我们可以使用任何我们能想象到的东西。以下实现动态交替。我没有使用队列,而是将所有接收到的迭代器存储在一个数组中:

import java.util.Iterator;

/**Alternates on the given iterators.*/
public class AlternatingIterator<E> implements Iterator {

    /**Stores the iterators which are to be alternated on.*/
    private Iterator<E>[] iterators;

    /**The index of iterator, which has the next element.*/
    private int nextIterator = 0;

    /**Initializes a new AlternatingIterator object.
     * Stores the iterators in the iterators field.
     * Finds the first iterator with an available element.*/
    public AlternatingIterator(Iterator<E> ... iterators) {
        this.iterators = iterators;

        if (!iterators[0].hasNext())
            findNextIterator();
    }

    @Override
    public boolean hasNext() {
        return iterators[nextIterator].hasNext();
    }

    @Override
    public Object next() {
        E element = iterators[nextIterator].next();

        findNextIterator();

        return element;
    }

    /**Steps on iterators, until one has next element.
     * It does not step on them infinitely, stops when
     * the lastly used iterator is reached.*/
    private void findNextIterator() {
        int currentIterator = nextIterator;

        // Finding iterator with element remaining.
        do {
            stepNextIterator();
        } while (!iterators[nextIterator].hasNext() && nextIterator != currentIterator);
        // If it gets around to the same iterator, then there is no iterator with element.
    }

    /**Increases the nextIterator value without indexing out of bounds.*/
    private void stepNextIterator() {
        nextIterator = (nextIterator + 1) % iterators.length;
    }

}

但同样可以使用队列静态地进行,将迭代器中的所有元素排入队列,在您(您的教授)代码中只有一个队列。

@Andy Turner:从迭代器中收集元素导致在没有获得最后一个元素之前一直不依赖源集合。当然,从 Java8 开始,我们使用 Streams,它不会给我们带来并发异常,但在 Java8 之前,在我看来,将一个/更多迭代器缓冲到一个集合中可能会更安全。

编辑:你写了然后我们可以使用给定集合的迭代器。是的,我完全忘记了,为一个简单的队列实现一个迭代器肯定是没有意义的:)

【讨论】:

  • 太棒了。我都明白了。非常感谢。
【解决方案2】:

队列在这里很有帮助,但在您使用它的方式上没有帮助。

将提供给构造函数的迭代器中的所有元素复制到队列中,然后从该队列中实现自定义迭代器并没有真正意义:如果您要将元素放入已经实现 @987654321 的集合中@,你也可以直接使用Iterable的迭代器。

但这也可能不是练习的重点:您可以懒惰地使用输入迭代器。 (此外,如果其中一个迭代器是无限的怎么办......)

我建议的想法是创建一个 迭代器 的队列,而不是元素。这是您如何做到这一点的描述;我不想给你代码来破坏你的学习体验:

  • 在您的构造函数中,将参数中的迭代器放入队列中。
  • 要实现hasNext(),将迭代器从hasNext() 为假的队列头部弹出;当队列头部的迭代器有下一个元素(在这种情况下返回 true)或队列为空(在这种情况下返回 false)时停止。
  • 要实现next(),将头迭代器从队列中弹出,并获取它的下一个元素:这就是您将返回的内容。但是,在此之前,如果迭代器有更多元素,请将其推到队列的尾部(这样做意味着您将在下一次迭代中查看下一个迭代器)。

【讨论】:

    猜你喜欢
    • 2021-03-28
    • 1970-01-01
    • 2011-07-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-06-18
    • 1970-01-01
    相关资源
    最近更新 更多