2010-02-28 326 views
36

我使用泛型在java中創建了一個鏈表,現在我希望能夠遍歷列表中的所有元素。在C#中,我將在鏈表中使用yield return,同時檢查列表中包含的元素列表。在Java中的收益率返回

我該如何去創建一個java版本的上面,我可以遍歷鏈表中包含的所有項目?

我期待能夠編寫代碼ALA

LinkedList<something> authors = new LinkedList<something>(); 
for (Iterator<something> i = authors.Values ; i.HasNext()) 
     doSomethingWith(i.Value); 

,並認爲價值「屬性」 /法將包括代碼類似於

LinkedListObject<something> current = first; 
While (current != null){ 
yield return current.getValue(); 
current = current.getNext() 
} 

編輯:請注意,我對使用任何第三方API不感興趣。僅內置Java功能。

+0

的http:// stackoverflow.com/questions/1980953/is-there-a-java-equivalent-to-cs-yield-keyword – 2010-02-28 19:54:29

+2

我不知道C#。好奇,收益率回報是什麼? – bragboy 2010-02-28 19:59:30

+0

檢查此:http://msdn.microsoft.com/en-us/library/9k7k7cf0(VS.80).aspx – 2010-02-28 20:02:20

回答

-21

我在這裏錯過了什麼嗎?已經有java.util.LinkedList,它是完全泛型啓用的,它有一個返回Iterator的方法。

如果你真的想重新發明輪子,我建議你看看創建LinkedListIterator類,可能實現ListIterator。它會記住它在鏈接列表中的當前位置並在每次連續呼叫時提前。

+2

創建我自己的數據結構的原因是由於後續在進程中對性能增強的廣泛需求(可能不適用於鏈表和散列表)。您使用子類迭代器的解決方案是我最終用來解決手頭問題的解決方案。 – 2010-03-01 18:04:34

+22

我想你可能會錯過一些東西(就像OP一樣)。 C#/ .Net中的「yield return」只創建一個迭代器。如果迭代器的使用者提前終止,那麼產生迭代的循環也是如此。一個無限生成器就是這樣一個例子,如果沒有一個迭代器沒有使用集合作爲中間步驟的話,這是不可能的。對於他們給出的例子,你當然只是從'LinkedList'返回迭代器。 – 2012-09-19 18:45:38

-1

我試圖理解做什麼產量但沒有C#的經驗我不知道如果我有,但我會盡量嘗試...

我建議以下...

Something answer = null; 
for (Something author: authors){ 

    if (author.equals("Tom Jones"){ 
    answer = author; 
    break; 
    } 
} 

當談到從方法返回i的值會做以下...

public LinkedList<something> getAuthors(LinkedList<something> list){ 
     LinkedList<something> ret = new LinkedList<something>(); 
     for (something s:list){ 
     if (s.equals("abc")) 
      ret.add(s); 
     } 
     return ret; 
    } 

我失去了陰謀嗎?

+0

你在哪裏調用getAuthors(LinkedList)? – bragboy 2010-02-28 20:42:17

+0

ummm ...您可以從代碼中的任何位置調用getAuthors。如果你創建一個名爲Utils的類(作爲例子)並且使得該方法是靜態的,那麼你可以說Utils.getAuthors(在這裏傳遞你的列表);這將返回你的新列表。 – Paul 2010-02-28 20:57:33

+4

我遲到了,但您需要了解的是,在C#中,只有在調用IEnumerable的「MoveNext()」方法後纔會執行yield return語句。 IEnumerable中的項目被懶惰地評估,而不是你的例子。 – GuiSim 2012-01-19 15:53:37

-1

如果您需要yield return的完整功能,您可能需要將其設置爲兩個線程 - 一個用於第一個方法,一個用於第二個方法。然後,第一個線程應該wait,直到第二個線程將其值置於可訪問的位置並且它已準備就緒。然後,第一個線程將處理該值,wait爲下一個值,等等。

+0

我認爲你已經與http://en.wikipedia.org/wiki/Coroutine – MartinP 2015-01-07 17:58:39

4

我不明白爲什麼人們在討論線程......有什麼我不知道的收益率?

根據我的理解,yield return只是保存方法堆棧並在稍後恢復。要實現良率回報,您只需手動保存狀態。有關詳細信息,請參閱Java迭代器類,但對於鏈接列表,您可以保存當前項目。對於一個數組,你只需要索引。

+0

混淆線程。這是正確的。收益率和收益率回報不使用C#中的線程。他們進行編譯時轉換並創建一個狀態機,但該狀態機不使用任何額外的線程(儘管它可能是線程安全的)。 – 2012-02-22 12:08:04

1

只是爲了幫助讀者瞭解小細節。

如果您創建一個包含所有結果元素並返回列表的新列表,那麼這是一個很好的實現,很簡單,可以編寫代碼。您可以根據需要獲得有趣的數據結構,並在掃描正確的條目時,返回所有匹配的列表,並且您的客戶端將在列表中進行迭代。

如果你想保存一個狀態,它可能會更復雜。每次調用函數時,都需要到達你曾經去過的地方。更不用說重入問題等。

帶線程的解決方案不會創建新的列表。它和第一種解決方案一樣簡單。唯一的問題是你涉及一個線程同步,這是更難編碼,並有其性能處罰。

所以,是的,良率回報是偉大的,從Java中缺少。但是有一些解決方法。

30

您可以返回Iterable的匿名實現。效果非常相似,只是這是更詳細的。

public Iterable<String> getStuff() { 
    return new Iterable<String>() { 

     @Override 
     public Iterator<String> iterator() { 
      return new Iterator<String>() { 

       @Override 
       public boolean hasNext() { 
        // TODO code to check next 
       } 

       @Override 
       public String next() { 
        // TODO code to go to next 
       } 

       @Override 
       public void remove() { 
        // TODO code to remove item or throw exception 
       } 

      }; 
     } 
    }; 
} 
13

「yield return」是一個非常複雜的編譯器技巧。它基本上可以讓你聲明性地實現IEnumerable,而不需要任何「搞清」如何構建你的迭代器的煩人細節。不幸的是,它並沒有很好地翻譯成其他語言,因爲很少有編譯器具有這樣的功能。在某些方面,「收益回報」與革命一樣具有侵略性。

基本上在C#中,編譯器會生成兩個IEnumerable和IEnumerator(T)的實現。它通過基本實現「方法」的局部變量作爲生成的實現類中的實例字段以及檢查包含「收益返回」工件的幀來完成此操作。一旦你知道了這一點,一個全面的開發者應該可以明確地完成同樣的事情......儘管不夠簡潔。爲了演示,我會CONCAT!

public static <T> Iterable<T> concat(Iterable<T> x, Iterable<T> y) 
{ 
    for(T e: x) 
    { 
     yield return e; 
    } 

    for(T e: y) 
    { 
     yield return e; 
    } 
} 

// becomes .... 

public static <E> Iterator<E> concat_(Iterable<E> x, Iterator<E> y) 
{ 
    T e1, e2; 
    Iterator<E> i1, i2; 

    Iterator<E> s; 
    Iterator<E> s4 = new Iterator<E>() 
    { 
     public bool hasNext() 
     { 
      return false; 
     } 

     public E next() 
     { 
      throw ... ; 
     } 

     public void remove() 
     { 
      throw ... ; 
     } 
    } 

    Iterator<E> s3 = new Iterator<E>() 
    { 
     Iterator<E> act() 
     { 
      if(i2.hasNext()) 
      { 
       return i2; 
      } 

      i2 = y.iterator(); 
      return (s = s4); 
     } 

     public bool hasNext() 
     { 
      return act().hasNext(); 
     } 

     public E next() 
     { 
      return act().next(); 
     } 

     public void remove() 
     { 
      return i2.remove(); 
     } 
    } 

    Iterator<E> s2 = new Iterator<E>() 
    { 
     Iterator<E> act() 
     { 
      if(i1.hasNext()) 
      { 
       return i1; 
      } 

      i2 = y.iterator(); 
      return (s = s3); 
     } 

     public bool hasNext() 
     { 
      return act().hasNext(); 
     } 

     public E next() 
     { 
      return act().next(); 
     } 

     public void remove() 
     { 
      return i1.remove(); 
     } 
    }; 

    Iterator<E> s1 = new Iterator<E>() 
    { 
     Iterator<E> act() 
     { 
      i1 = x.iterator(); 
      return s = s2; 
     } 

     public bool hasNext() 
     { 
      return act().hasNext(); 
     } 

     public E next() 
     { 
      return act().next(); 
     } 

     public void remove() 
     { 
      return act().remove(); 
     } 
    }; 

    s = s1; 
    return new Iterator<T>() 
    { 
     public bool hasNext() 
     { 
      return s.hasNext(); 
     } 

     public E next() 
     { 
      return s.next(); 
     } 

     public void remove() 
     { 
      return s.remove(); 
     } 
    }; 
} 

public static <T> Iterable<T> concat(Iterable<T> x, Iterable<T> y) 
{ 
    return new Iterable<T>() 
    { 
     public Iterator<T> iterator() 
     { 
      return concat_(x, y) 
     } 
    }; 
} 

// tada! 

如果你都將原諒我3AM僞java的...