如何将迭代器复制到另一个迭代器?

时间:2015-04-30 07:20:50

标签: java iterator

我需要为for循环的每次迭代迭代一组值,但只有第一次迭代才能正常工作。此后itr.hasNext()返回false

Iterator<String> itr = getQuestionIterator(File file);

for(Person p : persons)
{
    while(itr.hasNext())
    {
        String question = itr.next();
        ........
        ........
    }
}

这种行为对我很清楚。

一个解决方案可能是在for循环中调用getQuestionIterator(File file)方法,因此对于每个for循环迭代,它都会重新初始化。但这是非常低效的方法,因为itr是独立的。

我尝试了这个Iterator<String> temp = itr,但它也不起作用,因为它仅包含引用。

有没有办法将迭代器复制到另一个或其他更好的方法?

3 个答案:

答案 0 :(得分:21)

Iterator是可以按顺序处理数据的最小API,因此它从底层数据源中抽象出来。因为它只能向前移动(next())而没有任何重置或倒带选项,所以它是一个单向对象,必须在使用后丢弃。由于它提供的API有限,因此不可能在不知道实现和/或底层数据源的情况下简单地“复制”它。

因此有四种方法可以解决您的问题:

(1)从基础数据源重新获取新迭代器

每次需要迭代数据时再次调用getQuestionIterator(File file)

  • 优点:易于使用,易于实施。无需缓存。
  • 缺点:性能(例如,必须再次读取/解析文件)。在此期间,基础数据源可能已被更改。

(2)将所有处理代码合并为一个迭代循环

而不是......

while (iterator.hasNext()) { /* first processing step */ }
while (iterator.hasNext()) { /* second processing step */ }
while (iterator.hasNext()) { /* third processing step */ }
...

...结合所有步骤:

while (iterator.hasNext()) {
    String question = iterator.next();
    /* first processing step */
    /* second processing step */
    /* third processing step */
    ...
}
  • 优点:只需要一个迭代器。无需缓存。
  • 缺点:并非总是可能,例如如果处理步骤有依赖关系。

(3)将所有元素复制到本地缓存(Collection

迭代所有项目并将它们放入可用于获取任意数量的迭代器的本地集合中:

// read everything into a local cache
Collection<String> cache = new ArrayList<>();
while (iterator.hasNext()) cache.add(iterator.next());

// now you can get as many iterators from cache as required:
Iterator<String> iter = cache.iterator();
// use iter

iter = cache.iterator(); // once more
// use iter
...
  • 优点:一旦所有数据都在缓存中,就可以快速实现。
  • 缺点:需要额外的缓存内存。

(4)修改您的数据源API,让其实现处理问题

含义:更改getQuestionIterator(File file)以返回Iterable<String>而不是Iterator<String>。您可以从Iterable

获得任意数量的迭代器
Iterable<String> iterable = getQuestionIterator(File file);
Iterator<String> iter = iterable.iterator();
// use iter

iter = iterable.iterator(); // once more
// use iter
  • 优势:基础数据源最了解如何缓存数据。如果基础数据源已使用缓存,则无需复制数据。
  • 缺点:并不总是可以更改API。

答案 1 :(得分:19)

这取决于你的代码块的确切内容,但为什么不翻转循环呢?让外部循环遍历文件,并且对于每次迭代,遍历所有Person s:

Iterator<String> itr = getQuestionIterator(File file);
while(itr.hasNext()) 
{
    String question = itr.next();
    for(Person p : persons)
    {    
        ........
        ........
    }
}

答案 2 :(得分:10)

您只能迭代Iterator一次。

如果您需要&#34;重置&#34;它,并重新创建迭代器是昂贵的(如从文件中读取),您可以将数据复制到临时集合(如ArrayList)。但是这需要足够的记忆来同时保存所有内容。

另一种方法可能是(取决于你的程序所做的)交换循环嵌套的顺序:迭代你的迭代器只需一次,然后迭代你内部循环中的Person(因为你已经拥有了所有这些在记忆中)。显然,这会以不同的顺序处理事情,这可能会也可能不容易适应你。