如何将迭代器复制到另一个迭代器?
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
,但它也没有用,因为它只包含参考。
有没有办法将迭代器复制到另一个或任何其他更好的方法?
这取决于您的代码块的确切内容,但为什么不翻转循环呢?让外部循环遍历文件,并且对于每次迭代,遍历所有 Person
s:
Iterator<String> itr = getQuestionIterator(File file);
while(itr.hasNext())
{
String question = itr.next();
for(Person p : persons)
{
........
........
}
}
您只能迭代一次迭代器。
如果您需要 "reset" 它,并且重新创建 Iterator 是昂贵的(例如从文件中读取),您可以将数据复制到临时集合(例如 ArrayList)中。但这需要足够的内存来同时保存所有内容。
另一种方法可能是(取决于你的程序做什么)交换循环嵌套的顺序:迭代你的迭代器一次,然后在内部循环中迭代你的Person
s(因为你已经有所有那些在记忆中)。显然,这会以不同的顺序处理事情,这对您来说可能容易也可能不容易适应。
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。
我需要为 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
,但它也没有用,因为它只包含参考。
有没有办法将迭代器复制到另一个或任何其他更好的方法?
这取决于您的代码块的确切内容,但为什么不翻转循环呢?让外部循环遍历文件,并且对于每次迭代,遍历所有 Person
s:
Iterator<String> itr = getQuestionIterator(File file);
while(itr.hasNext())
{
String question = itr.next();
for(Person p : persons)
{
........
........
}
}
您只能迭代一次迭代器。
如果您需要 "reset" 它,并且重新创建 Iterator 是昂贵的(例如从文件中读取),您可以将数据复制到临时集合(例如 ArrayList)中。但这需要足够的内存来同时保存所有内容。
另一种方法可能是(取决于你的程序做什么)交换循环嵌套的顺序:迭代你的迭代器一次,然后在内部循环中迭代你的Person
s(因为你已经有所有那些在记忆中)。显然,这会以不同的顺序处理事情,这对您来说可能容易也可能不容易适应。
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。