2013-04-16 22 views
7

Was ist der beste Weg, um eine Liste während der Verarbeitung von 2 Elementen gleichzeitig zu durchlaufen?Java - Iterieren über alle zwei Elemente in einer Liste

Beispiel:

List<String> strings = Arrays.asList("item 1", "item 2", "item 3", "item 4"); 
for(int i = 0; i < strings.size(); i++){ 
    String first = strings.get(i); 
    String second = null; 
    if(strings.size() > i + 1){ 
     second = strings.get(i + 1); 
    } 
    System.out.println("First [" + first + "] - Second [" + second + "]"); 
} 

Ergebnisse in:

First [item 1] - Second [item 2] 
First [item 2] - Second [item 3] 
First [item 3] - Second [item 4] 
First [item 4] - Second [null] 

Ich mag würde erreichen:

First [item 1] - Second [item 2] 
First [item 3] - Second [item 4] 

Antwort

11

Gerade i erhöhen 2:

for(int i = 0; i < strings.size(); i += 2) { 
+0

kann das nicht außerhalb der Grenzen gehen? – CQM

+0

@CQM Wenn es eine ungerade Anzahl von Elementen gibt, dann ja. Um das zu vermeiden, verwenden Sie 'int validSize = string.size() & ~1; 'und verwenden Sie diese in einer Schleife. – hyde

7

Sie benötigen i für den zweiten Wert zu ändern und zu erhöhen, ändern Sie die Aussage:

second = strings.get(i + 1); 

zu

second = strings.get(++i); 

Dies wird die i auch erhöhen, da dies das gewünschte Verhalten zu sein scheint.

So würde Ihr Code sein:

List<String> strings = Arrays.asList("item 1", "item 2", "item 3", "item 4"); 
for(int i = 0; i < strings.size(); i++){ 
    String first = strings.get(i); 
    String second = null; 
    if(strings.size() > i + 1){ 
     second = strings.get(++i); //Change here 
    } 
    System.out.println("First [" + first + "] - Second [" + second + "]"); 
} 
+0

ich halten würde die Indexvariable zu ändern nur im 3. Teil der for-Anweisung. Wenn Sie es an mehreren Stellen innerhalb der Schleife erhöhen, wird der Code weniger klar (dh schwerer zu verstehen und zu pflegen, leichter zu Bugs). Dies ist eine ziemlich häufige Idiom/Faustregel mit for-Schleife, und While-Schleife könnte die bessere Wahl sein, wenn Sie es auf Ihre Weise schreiben. – hyde

+2

@ Hyde, ich dachte darüber nach, aber dann beschlossen, Minimum zu ändern, für das OP Verständnis, ich stimme zu, dass für den Zähler sollte nur an einem einzigen Ort geändert werden, da es besseres Verständnis/Lesbarkeit bietet – Habib

+0

Danke Jungs, beide Antworten waren wirklich hilfreich! – stikkos

2

Was ist, wenn Sie i in jeder Iteration um 2 erhöhen? Sollte tun ... Andernfalls i innerhalb der eigentlichen Schleife erhöhen

0
for(int i = 0; i < strings.size(); i++){ 
    String first = strings.get(i++); 
    String second = null; 
    if(strings.size() > i){ 
     second = strings.get(i); 
    } 
    System.out.println("First [" + first + "] - Second [" + second + "]"); 
} 
2
List<String> strings = Arrays.asList("item 1", "item 2", "item 3", "item 4");  
int i = 0; 
for(; i < strings.size() - 1; i+=2){ 
    String first = strings.get(i); 
    String second = strings.get(i + 1); 
    System.out.println("First [" + first + "] - Second [" + second + "]"); 
} 
//For odd sized lists 
if(i < strings.size()){   
    System.out.println("First [" + strings.get(i) + "]"); 
} 
+0

Gibt es einen Grund, warum Sie das "int i = 0" außerhalb der Schleife setzen? –

+0

@MarcoForberg: Yes.Um die Überprüfung für ungerade Größe Liste außerhalb der 'for' Schleife – Cratylus

+0

hmmm in Ordnung, aber warum nicht für ungerade Größe" wie üblich "zu überprüfen:' strings.size()% 2'? uhmm ... korrigiere mich, wenn ich falsch liege, aber nach der Ausführung der Schleife denke ich, dass ich um eins größer sein werde als die Größe der Liste. –

0
List<String> strings = Arrays.asList("item 1", "item 2", "item 3", "item 4"); 
for(int i = 0; i < strings.size(); i++){ 
    if(i½2 = 0){ 
     String first = strings.get(i); 
     System.out.print("First [" + first + "] "); 
    }else{ 
     String second = strings.get(i + 1); 
     System.out.println("- Second [" + second + "]"); 
    } 
} 
0

Für Leistung, werde ich empfehlen Ihnen, die zu berechnen Größe der Liste nur eine und keine neue Zeichenfolge bei jeder neuen Schleife erstellen.

List<String> strings = Arrays.asList("item 1", "item 2", "item 3", "item 4"); 
int length = strings.size(); 
String first, second = null; 
for(int i = 0; i < length; i += 2){ 
    ... 
} 
+3

Meinung: Aufruf zu 'strings.size()' wird inline, so Leistungsdifferenz ist vernachlässigbar. Auch oft (vielleicht in diesem Fall) können solche Optimierungen zu Bugs werden, wenn Code später geändert wird, aber das Aktualisieren des vorberechneten Wertes wird vergessen. Es ist nützlich, diese Art von Optimierung zu betrachten, aber es sollte nur dann gemacht werden, wenn es sich um eine echte Verbesserung der Leistung (z. B. Berechnung der Größe ist teuer) oder der Lesbarkeit (Größe wird z. B. an mehreren Stellen berechnet) handelt. . Ansonsten, wie hier, ist es eine vorzeitige Mikrooptimierung und IMNSHO sollte vermieden werden. – hyde

+0

Ich stimme Ihnen zu, dass Sie für einen ersten Prototyp der Lösung nicht an Optimierung denken. Aber in realen Situationen behandeln Sie große Datenmengen. Also ich denke, es sollte als eine gute Praxis betrachtet werden – Lahniep

+1

"in der realen Welt Situationen, die Sie mit großen Datenmengen umgehen" ist meiner Meinung nach ein bisschen eine Verallgemeinerung. Große Datenmengen, die Leistungsoptimierungen erfordern, sind außergewöhnlich, sogar in realen Situationen! – stikkos

1

Wir sollten natürlich eine Lösung für den allgemeinen Fall liefern ;-)

public static void main(String[] args) { 
    List<Integer> list = Arrays.asList(new Integer[] { 1, 2, 3, 4, 5, 6, 7, 8, 9 }); 
    for (Pair<Integer> p : Pair.over(list)) { 
     System.out.printf("%d, %d\n", p.first, p.second); 
    } 
} 

static class Pair<T> { 
    T first; 

    T second; 

    public Pair(T first, T second) { 
     this.first = first; 
     this.second = second; 
    } 

    public static <T> Iterable<Pair<T>> over(Collection<T> collection) { 
     return new PairWise<T>(collection); 
    } 

    private static class PairWise<T> implements Iterable<Pair<T>>, Iterator<Pair<T>> { 

     final Iterator<T> iterator; 

     PairWise(Collection<T> collection) { 
      super(); 
      this.iterator = collection.iterator(); 
     } 

     @Override 
     public Iterator<Pair<T>> iterator() { 
      return this; 
     } 

     @Override 
     public boolean hasNext() { 
      return iterator.hasNext(); 
     } 

     @Override 
     public Pair<T> next() { 
      T first = null; 
      T second = null; 
      if (iterator.hasNext()) 
       first = iterator.next(); 
      else 
       throw new NoSuchElementException(); 
      if (iterator.hasNext()) 
       second = iterator.next(); 
      return new Pair<T>(first, second); 
     } 

     @Override 
     public void remove() { 
      throw new UnsupportedOperationException(); 
     } 

    } 
} 
0

Sie Indizierung mit einem Iterator vermeiden können; Dies funktioniert für jede Iterable, nicht nur eine Liste. Nur einen Iterator bekommen und es zweimal pro Schleife erhöhen Iteration:

List<String> strings = Arrays.asList("item 1", "item 2", "item 3", "item 4"); 
Iterator<String> stringsIterator = strings.iterator(); 
while (stringsIterator.hasNext()) { 
    String first = stringsIterator.next(); 
    String second = stringsIterator.next(); 
    System.out.println("First [" + first + "] - Second [" + second + "]"); 
} 

Dies setzt voraus, eine Liste von gleicher Länge und wirft NoSuchElementException am letzten Pass, wenn sie ungerade Länge ist. Sie können dies auf verschiedene Weise handhaben:

  • eine try verwenden - catch;
  • haben eine Wächterklausel, die überprüft, dass die Länge gerade vorher ist;
  • überprüfen, bevor Sie das zweite Element erhalten.

Überprüfen des zweiten Elements:

List<String> strings = Arrays.asList("item 1", "item 2", "item 3"); 
Iterator<String> stringsIterator = strings.iterator(); 
while (stringsIterator.hasNext()) { 
    String first = stringsIterator.next(); 
    String second = stringIterator.hasNext() ? stringIterator.next() : null; 
    System.out.println("First [" + first + "] - Second [" + second + "]"); 
} 

Iteratoren einige Leute verwirren, so dass Sie auch eine für-jede Schleife mit einem Zweig und einem Hilfs Flip-Flop-Variable für die Parität verwenden können. Dies ist viel schlimmer, da es die Logik der Schleife viel komplizierter macht, um die Iteration zu vereinfachen: anstatt die Aktion einmal pro Durchgang durch die Schleife nacheinander und ohne Verzweigung durchzuführen, müssen Sie sie stattdessen zweimal durchlaufen und mental verzweigen. Beachten Sie, dass dies das letzte Element überspringt, wenn es eine ungerade Länge hat; könnte nachträglich eine Überprüfung von isFirst hinzufügen, wenn auch diese Fälle behandelt werden sollen.

List<String> strings = Arrays.asList("item 1", "item 2", "item 3", "item 4"); 
boolean isFirst = true; 
String first = null; 
String second = null; 
for (String string : strings) { 
    if (isFirst) { 
    first = string; 
    isFirst = false; 
    } else { 
    second = string; 
    isFirst = true; 
    System.out.println("First [" + first + "] - Second [" + second + "]"); 
    } 
} 

Schließlich beachten Sie, dass alle diese Iteratoren und Hilfsgrößen haben überschüssigen Umfang (sie nur dann von Nutzen für die Schleife selbst sind, so dass sie verschmutzen die lokale Umgebung): sie in Blöcken eingewickelt werden, um den Umfang zu begrenzen, obwohl in der Regel wird die resultierende Verschachtelung schlechter angesehen als der Überschuss -umfang:

List<String> strings = Arrays.asList("item 1", "item 2", "item 3", "item 4"); 
{ 
    Iterator<String> stringsIterator = strings.iterator(); 
    while (stringsIterator.hasNext()) { 
    String first = stringsIterator.next(); 
    String second = stringsIterator.next(); 
    System.out.println("First [" + first + "] - Second [" + second + "]"); 
    } 
} 
+0

Diese Hausaufgabe war vor zwei Jahren ... – Superfy

+0

Es ist eine grundlegende Frage, aber eine saubere Antwort (ohne Indizierung) ist ein bisschen subtil. Dieses Problem taucht im wirklichen Leben auf (und entstand für mich, so kam ich hierher), wenn Sie eine Liste von abgeflachten Paaren haben, wie '[a0, b0, a1, b1, ...]'. –

5

Ich habe die folgende Methode ein Java8 BiConsumer mit:

public static <T> void tupleIterator(Iterable<T> iterable, BiConsumer<T, T> consumer) { 
    Iterator<T> it = iterable.iterator(); 
    if(!it.hasNext()) return; 
    T first = it.next(); 

    while(it.hasNext()) { 
     T next = it.next(); 
     consumer.accept(first, next); 
     first = next; 
    } 
} 

es wie folgt verwendet werden:

List<String> myIterable = Arrays.asList("1", "2", "3"); 
tupleIterator(myIterable, (obj1, obj2) -> { 
    System.out.println(obj1 + " " + obj2); 
}); 

erhalten Sie folgende Ausgabe:

1 2 
2 3 
Verwandte Themen