2015-04-30 11 views
16

Ich muss über die Menge der Werte für jede Wiederholung der for-Schleife, aber nur für die erste Iteration es funktioniert gut. Danach gibt das itr.hasNext()false zurück.Wie kopiert man einen Iterator in einen anderen?

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

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

Dieses Verhalten ist mir klar.

Eine Lösung könnte getQuestionIterator(File file) Methode in For-Schleife aufrufen, so dass für jede Schleife Iteration es reinitialisiert wird. Dies ist jedoch ein sehr ineffizienter Ansatz, da itr unabhängig ist.

Ich versuchte dies Iterator<String> temp = itr, aber es funktionierte auch nicht, da es nur die Referenz enthält.

Gibt es eine Möglichkeit, den Iterator in einen anderen oder einen anderen besseren Ansatz zu kopieren?

+4

Der einfachste Weg besteht darin, jedes Mal einen neuen Iterator zu erstellen. Siehe http://stackoverflow.com/questions/7689261/why-iterator-doesnt-have-any-reset-method – NaN

+1

Wenn dies bedeutet, dass 'getQuestionIterator()' ein teurer Aufruf ist (dh, es gibt Datei-I/O) , können Sie geladene Fragen in einige In-Memory-Sammlung speichern und durchlaufen sie über alle außer ersten Schleife der äußeren Schleife ('für (Person)') –

+1

Wieder geöffnet, weil es scheint, der Iterator ist teuer, neu zu erstellen (die nicht gesetzt wurde in der Duplikatfrage). – Thilo

Antwort

21

Eine Iterator ist die kleinstmögliche API zum sequentiellen Abarbeiten von Daten, daher abstrahiert sie von der zugrunde liegenden Datenquelle. Da es nur vorwärts gehen kann (next()), ohne eine Option zum Zurücksetzen oder Zurückspulen, ist es ein Einwegobjekt, das nach der Verwendung weggeworfen werden muss. Und aufgrund der begrenzten API ist es nicht möglich, sie einfach zu "kopieren", ohne die Implementierung und/oder die zugrunde liegende Datenquelle zu kennen.

So gibt es vier Möglichkeiten, um Ihr Problem zu behandeln:

(1) Re-aquire einen neuen Iterator aus der zugrunde liegenden Datenquelle

Gerade getQuestionIterator(File file) rufen jedes Mal, wenn Sie über die Daten zu durchlaufen müssen (nochmal).

  • Vorteil: Einfach zu bedienen, einfach zu implementieren. Kein Cache erforderlich.
  • Nachteil: Leistung (z. B. Datei muss erneut gelesen/geparst werden). Die zugrunde liegende Datenquelle wurde möglicherweise in der Zwischenzeit geändert.

(2) Kombinieren aller Verarbeitungscode in eine einzige Schleife Iterieren

Statt ...

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

... kombinieren alle Schritte:

while (iterator.hasNext()) { 
    String question = iterator.next(); 
    /* first processing step */ 
    /* second processing step */ 
    /* third processing step */ 
    ... 
} 
  • Vorteil: Nur ein Iterator erforderlich. Kein Cache erforderlich.
  • Nachteil: Nicht immer möglich, z.B. wenn Verarbeitungsschritte Abhängigkeiten haben.

(3) Kopieren Sie alle Elemente in einem lokalen Cache (Collection)

Iterate über alle Positionen einmal und sie in eine lokale Sammlung setzen, die Sie verwenden können eine beliebige Anzahl von Iteratoren zu erwerben:

// 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 
... 
  • Vorteil: Einfach, schnell, sobald alle Daten zu implementieren, ist im Cache.
  • Nachteil: Zusätzlicher Speicher für Cache erforderlich.

(4) Datenquelle API ändern ihre Umsetzung zu lassen, das Problem

Bedeutung Griff: getQuestionIterator(File file) Ändern eines Iterable<String> anstelle eines Iterator<String> zurückzukehren. Sie können eine beliebige Anzahl von Iteratoren von einem Iterable gewinnen:

Iterable<String> iterable = getQuestionIterator(File file); 
Iterator<String> iter = iterable.iterator(); 
// use iter 

iter = iterable.iterator(); // once more 
// use iter 
  • Vorteil: Die zugrunde liegende Datenquelle weiß am besten, wie Sie Ihre Daten zwischenzuspeichern. Sie müssen Ihre Daten nicht kopieren, wenn die zugrunde liegende Datenquelle bereits einen Cache verwendet.
  • Nachteil: Es ist nicht immer möglich, die API zu ändern.
19

Es kommt auf den genauen Inhalt Ihres Codeblocks an, aber warum nicht die Schleifen umkehren? Haben die äußere Schleife über die Datei gehen, und für jede Iteration, gehen über alle Person s:

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

Sie können nur einen Iterator einmal durchlaufen.

Wenn Sie es "zurücksetzen" müssen und das Erstellen des Iterators teuer ist (z. B. Lesen aus einer Datei), können Sie die Daten in eine temporäre Sammlung (z. B. eine ArrayList) kopieren. Aber das erfordert genug Speicher, um alles auf einmal zu halten. Ein anderer Ansatz könnte sein (hängt davon ab, was Ihr Programm tut), die Reihenfolge der Schleifenverschachtelung zu vertauschen: Iterieren Sie einfach einmal über Ihren Iterator und über Ihre Person s in der inneren Schleife (da Sie bereits alle im Speicher haben) . Offensichtlich verarbeitet dies Dinge in einer anderen Reihenfolge, die für Sie leicht oder nicht leicht zu bewältigen ist.

Verwandte Themen