Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to copy an iterator to another one?

Tags:

I need to iterate over the set of values for each iteration of for loop, but only for first iteration it works fine. Thereafter the itr.hasNext() returns false.

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

This behaviour is clear to me.

One solution could be calling getQuestionIterator(File file) method in for loop so for each for loop iteration it gets reinitialized. But this is very inefficient approach as itr is independent.

I tried this Iterator<String> temp = itr , but it didn't work also as it holds the reference only.

Is there any way to copy the iterator into another one or any other better approach?

like image 451
Amitsh Avatar asked Apr 30 '15 07:04

Amitsh


People also ask

Can you reuse an iterator?

iterators are not reusable; you need to get a fresh Iterator from the Iterable collection each time you want to iterate over the elements.

What does iterator next () do?

Iterator interface provides the following methods: boolean hasNext() - Returns true if the iteration has more elements. E next() - Returns the next element in the iteration. void remove() - Removes from the underlying collection the last element returned by the iterator (optional operation).

Is iterator better than for loop?

Iterator and for-each loop are faster than simple for loop for collections with no random access, while in collections which allows random access there is no performance change with for-each loop/for loop/iterator.


2 Answers

An Iterator is the smallest possible API to work off data sequentially, hence it abstracts from the underlying data source. As it can only move forwards (next()) without any option to reset or rewind, it is a one-way object that must be thrown away after usage. And due to the limited API it offers, it is not possible to simply "copy" it without knowing the implementation and/or the underlying data source.

So there are four ways to handle your problem:

(1) Re-aquire a new iterator from the underlying data source

Just call getQuestionIterator(File file) every time you need to iterate over the data (again).

  • Advantage: Easy to use, easy to implement. No cache required.
  • Disadvantage: Performance (e.g. file has to be read/parsed again). Underlying data source might have been changed in the meantime.

(2) Combine all processing code into one single iterating loop

Instead of...

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 */ } ... 

...combine all steps:

iterator = /* get new iterator */ while (iterator.hasNext()) {     String question = iterator.next();     /* first processing step */     /* second processing step */     /* third processing step */     ... } 
  • Advantage: Only one iterator required. No cache required.
  • Disadvantage: Not always possible, e.g. if processing steps have dependencies.

(3) Copy all elements into a local cache (Collection)

Iterate over all items once and put them into a local collection that you can use to aquire an arbitrary number of iterators:

// 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 ... 
  • Advantage: Simple to implement, fast, once all data is in the cache.
  • Disadvantage: Additional memory for cache required.

(4) Modify your data source API to let its implementation handle the problem

Meaning: Change getQuestionIterator(File file) to return an Iterable<String> instead of an Iterator<String>. You can gain an arbitrary number of iterators from an Iterable:

Iterable<String> iterable = getQuestionIterator(File file); Iterator<String> iter = iterable.iterator(); // use iter  iter = iterable.iterator(); // once more // use iter 
  • Advantage: The underlying data source knows best how to cache your data. No need to copy your data in case the underlying data source already uses a cache.
  • Disadvantage: It is not always possible to change the API.
like image 162
isnot2bad Avatar answered Sep 27 '22 18:09

isnot2bad


It depends on the exact contents of your code block, but why not flip the loops? Have the outer loop go over the file, and for each iteration, go over all the Persons:

Iterator<String> itr = getQuestionIterator(File file); while(itr.hasNext())  {     String question = itr.next();     for(Person p : persons)     {             ........         ........     } } 
like image 32
Mureinik Avatar answered Sep 27 '22 19:09

Mureinik