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

Ami*_*tsh 19 java iterator

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

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

for(Person p : persons)
{
    while(itr.hasNext())
    {
        String question = itr.next();
        ........
        ........
    }
}
Run Code Online (Sandbox Code Playgroud)

这种行为对我来说很清楚.

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

我尝试了这个Iterator<String> temp = itr,但它也没有用,因为它仅保留了参考.

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

isn*_*bad 21

An 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 */ }
...
Run Code Online (Sandbox Code Playgroud)

...结合所有步骤:

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

(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
...
Run Code Online (Sandbox Code Playgroud)
  • 优点:一旦所有数据都在缓存中,操作简单快捷.
  • 缺点:需要额外的缓存内存.

(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
Run Code Online (Sandbox Code Playgroud)
  • 优势:底层数据源最了解如何缓存数据.如果基础数据源已使用缓存,则无需复制数据.
  • 缺点:并不总是可以更改API.


Mur*_*nik 19

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

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


Thi*_*ilo 10

您只能迭代Iterator一次.

如果需要"重置"它,并且重新创建迭代器很昂贵(例如从文件读取),则可以将数据复制到临时Collection(例如ArrayList)中.但这需要足够的内存来同时保存所有内容.

另一种方法可能是(取决于你的程序做什么)交换循环嵌套的顺序:迭代你的迭代器只需一次,然后Person在内循环中迭代你的s(因为你已经拥有了所有那些在内存中).显然,这会按照不同的顺序处理事情,这可能会也可能不容易为您提供.