2013-04-16 47 views
7

在處理2個元素的同時迭代列表的最佳方式是什麼?Java - 迭代列表中的每兩個元素

實例:

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 + "]"); 
} 

結果:

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

我想實現:

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

回答

11

只是增加i以2:

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

不能這樣出界嗎? – CQM

+0

@CQM如果元素數量不均勻,那麼是的。爲了避免這種情況,'int validSize = string.size()& ~1;'並在循環條件中使用它。 – hyde

7

您需要修改和增加i第二值,修改聲明:

second = strings.get(i + 1); 

second = strings.get(++i); 

這將遞增i爲好,因爲這似乎是期望的行爲。

所以,你的代碼是:

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

我會不斷變化的指標變量只在for語句的第三部分。在循環內的多個位置增加它會導致不太清晰(意味着難以理解和維護,更容易出現錯誤)代碼。這對於循環來說是非常常見的成語/經驗法則,while循環可能是更好的選擇,如果你按照自己的方式編寫它的話。 – hyde

+2

@hyde,我想過了,但後來決定改變最小值,對於OP的理解,我同意循環計數器應該只在一個地方修改,因爲它提供了更好的理解/可讀性 – Habib

+0

謝謝你們,兩個答案都是真的有幫助! – stikkos

2

如果你在每次迭代增加我的2?應該做的...... 否則考慮提高我的實際循環內

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

爲什麼你把'int i = 0'放在循環的外面? –

+0

@MarcoForberg:是的。要檢查'for'循環外的奇怪大小列表 – Cratylus

+0

嗯,但爲什麼不檢查奇怪的大小「照常」:'strings.size()%2'?嗯...糾正我,如果我錯了,但執行循環後,我想我會比列表的大小大一個。 –

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

出於性能考慮,我會建議你來計算列表大小隻有一個,並且不會在每個新循環中創建一個新字符串。

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

意見:調用'strings.size()'得到內聯,所以性能差異可以忽略不計。當代碼稍後改變時,通常(可能不是這種情況下)這樣的優化有可能成爲錯誤,但更新預先計算的值會被遺忘。 *考慮*這種優化是有用的,但是它只應該被完成*如果它是一個真正的性能改進(例如計算大小是昂貴的)或可讀性(例如大小在幾個地方計算) 。否則,像這樣,它是過早的微觀優化,應避免IMNSHO。 – hyde

+0

我同意你對解決方案的第一個原型,你不考慮優化。但是在現實世界中,您需要處理大量數據。所以我認爲這應該被認爲是一種好的做法 – Lahniep

+1

「在處理大量數據的現實世界中」在我看來有點泛泛。即使在現實世界的情況下,需要性能優化的大量數據也是非同尋常的! – stikkos

1

我們當然應該提供一般情況下;-)

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

可避免與Iterator索引的解決方案;這適用於任何Iterable,而不僅僅是一個列表。剛剛得到一個迭代,每個循環迭代增加了兩遍:

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 + "]"); 
} 

這是假設,即使長的列表,並在最後一關拋出NoSuchElementException,如果是奇數長度。您可以通過多種方式處理:

  • 使用try - catch;
  • 有一個保護條款,它會檢查長度是否在預先確定的範圍內;
  • 獲取第二個元素之前檢查。

檢查第二個元素:

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 + "]"); 
} 

迭代迷惑一些人,所以你也可以使用for-each循環用樹枝和奇偶校驗輔助觸發器變​​量。這更糟糕,因爲它使得循環的邏輯更加複雜以簡化迭代:而不是每次通過循環執行一次操作,而是按順序進行並且不需要分支,而是必須經過兩次並在心理上分支。請注意,如果它的長度爲奇數,則會跳過最後一個元素;如果想要處理這些情況,可以在之後添加isFirst的支票。

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 + "]"); 
    } 
} 

最後,注意,所有這些迭代器和輔助變量有多餘範圍(他們只使用了循環本身的,所以他們污染了當地的環境):可以把它們包裹在塊限制範圍,雖然平時所產生的嵌套被認爲比超出範圍更糟:

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

這個家庭作業問題來自兩年前... – Superfy

+0

這是一個基本的問題,但一個乾淨的答案(沒有索引)是有點微妙。這個問題出現在現實生活中(對我來說,這就是我來到這裏的時候),當你有一個扁平對列表時,比如'[a0,b0,a1,b1,...]'。 –

5

我創建使用Java8 BiConsumer以下方法:

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; 
    } 
} 

這樣使用它:

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

這將輸出:

1 2 
2 3 
相關問題