2012-11-20 98 views
15

我有一個LinkedList,我需要多次來回迭代。我正在使用它來跟蹤將在動態創建的工作流中的一系列頁面。這不符合我的預期。鑑於這個例子:使用ListIterator在Java中的LinkedList之間來回移動

LinkedList<String> navigationCases; 
navigationCases.add("page1"); 
navigationCases.add("page2"); 
navigationCases.add("page3"); 
navigationCases.add("page4"); 

ListIterator navigationItr = navigationCases.listIterator(); 
navigationItr.next(); // Returns page1 
navigationItr.next(); // Returns page2 
navigationItr.previous(); //Returns page2 again 
navigationItr.next(); //Returns page2 again 

我想也許我被錯誤地建立我的名單,或者使用迭代錯了,但閱讀文檔後,這似乎是由設計:

一個的ListIterator沒有當前元件;其遊標位置始終位於將調用previous()所返回的元素與調用next()所返回的元素之間。

和:

(下一頁)返回列表中的下一個元素。可以重複調用此方法來遍歷列表,或者與前一個調用混合以前後來回訪問。 (請注意,交替調用next和previous會重複返回相同的元素。)

所以在閱讀完此代碼之後,我很清楚爲什麼我的代碼的行爲方式如此。我只是不明白爲什麼它應該這樣工作。即使刪除似乎是向後彎曲,以適應這種實現:

請注意,remove()和set(Object)方法沒有根據光標位置定義;它們被定義爲在對next()或previous()的調用返回的最後一個元素上進行操作。

從概念上講,LinkedList似乎很好地模擬了我的工作流案例,但我無法使用這種方式運行的Iterator。我在這裏錯過了什麼,或者我應該寫我自己的班級維護一個案例列表並瀏覽它們?

+1

爲什麼你不能「使用這種方式的迭代器」?世界其他地區的確如此。只要接受它的工作原理,並按照它的意圖使用它即可。 – Madbreaks

+2

它的行爲方式是這樣的,因爲它通過從最終工作開始進行迭代和刪除,與從頭開始迭代和刪除完全相同。 –

+0

@Madbreaks這個用例與「打算使用」的方式有何不同?在要求下一個要求之後,我如何解釋要求先前要素的「特殊」情況?或者在詢問之前立即詢問下一個? – user1535568

回答

9

這應該做你的工作:

public class Main { 
    public static void main(String[] args) { 
     final LinkedList<String> list = new LinkedList<String>(); 

     list.add ("1"); list.add ("2"); list.add ("3"); list.add ("4"); 

     final MyIterator<String> it = new MyIterator (list.listIterator()); 

     System.out.println(it.next()); 
     System.out.println(it.next()); 
     System.out.println(it.next()); 
     System.out.println(it.previous()); 
     System.out.println(it.previous()); 
     System.out.println(it.next()); 
    } 

    public static class MyIterator<T> { 

     private final ListIterator<T> listIterator; 

     private boolean nextWasCalled = false; 
     private boolean previousWasCalled = false; 

     public MyIterator(ListIterator<T> listIterator) { 
      this.listIterator = listIterator; 
     } 

     public T next() { 
      nextWasCalled = true; 
      if (previousWasCalled) { 
       previousWasCalled = false; 
       listIterator.next(); 
      } 
      return listIterator.next(); 
     } 

     public T previous() { 
      if (nextWasCalled) { 
       listIterator.previous(); 
       nextWasCalled = false; 
      } 
      previousWasCalled = true; 
      return listIterator.previous(); 
     } 

    } 
} 

而一個fiddle爲了它。

+0

是的,我沒有看到任何方法必須記住以前的操作。謝謝! – user1535568

-1

做這樣的事情(僞) -

class SkipIterator extends ListIterator { 

    public E previous(){ 
     E n = super.previous(); 
     return super.previous(); 
    } 

    ... 

} 

則:

LinkedList<String> navigationCases; 
navigationCases.add("page1"); 
navigationCases.add("page2"); 
navigationCases.add("page3"); 
navigationCases.add("page4"); 

SkipIterator navigationItr = (SkipIterator)navigationCases.listIterator(); 
navigationItr.next(); // Returns page1 
navigationItr.next(); // Returns page2 
navigationItr.previous(); // Returns page1 

乾杯

+1

不幸的是,如果前面的操作是next(),我只想調用previous()兩次。如果next未被調用,調用previous()兩次實際上會導致迭代器跳過列表中的元素。 – user1535568

+0

好的,所以建立這個邏輯。:)想法是,你可以擴展基類幷包含你的用例需要的邏輯。 – Madbreaks

+0

是的你是對的。謝謝! – user1535568

0

ListIterator被設計爲表現這種方式。請參閱ShyJ回答下面的對話。

我發現這種行爲超出了白癡,而是寫了一個非常簡單的選擇。這裏的科特林代碼具有擴展功能的ArrayList:

class ListIterator<E>(var list: ArrayList<E>) : Iterator<E> { 

    private var cursor: Int = 0 

    fun replace(newList: ArrayList<E>) { 
     list = newList 
     cursor = 0 
    } 

    override fun hasNext(): Boolean { 
     return cursor + 1 < list.size 
    } 

    override fun next(): E { 
     cursor++ 
     return current() 
    } 

    fun hasPrevious(): Boolean { 
     return 0 <= cursor - 1 
    } 

    fun previous(): E { 
     cursor-- 
     return current() 
    } 

    fun current(): E { 
     return list[cursor] 
    } 

} 

fun <E> ArrayList<E>.listFlippingIterator() = ListIterator(this) 

如果您希望包括去除功能,我強烈建議寫API明確指示迭代器是否應該刪除左或右,例如通過將這些方法定義爲removeNext()removePrevious()