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

How to copy an iterator to another one?

我需要为 for 循环的每次迭代迭代值集,但仅对于第一次迭代它工作正常。此后itr.hasNext()returnsfalse

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 ,但它也没有用,因为它只包含参考。

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

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

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

您只能迭代一次迭代器。

如果您需要 "reset" 它,并且重新创建 Iterator 是昂贵的(例如从文件中读取),您可以将数据复制到临时集合(例如 ArrayList)中。但这需要足够的内存来同时保存所有内容。

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

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

所以有四种方法可以解决你的问题:

(1)从底层数据源重新获取一个新的迭代器

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

  • 优点:易于使用,易于实施。无需缓存。
  • 缺点:性能(例如,文件必须再次 read/parsed)。基础数据源可能已同时更改。

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

而不是...

iterator = /* get new iterator */
while (iterator.hasNext()) {
    String question = iterator.next();
    /* first processing step */
}
iterator = /* get new iterator */
while (iterator.hasNext()) {
    String question = iterator.next();
    /* second processing step */
}
iterator = /* get new iterator */
while (iterator.hasNext()) {
    String question = iterator.next();
    /* third processing step */
}
...

...合并所有步骤:

iterator = /* get new iterator */
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) 更改为 return 和 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。