2010-02-28 36 views
36

Tôi đã tạo một danh sách liên kết trong java bằng cách sử dụng Generics, và bây giờ tôi muốn có thể lặp qua tất cả các phần tử trong danh sách. Trong C#, tôi sẽ sử dụng yield return bên trong danh sách được liên kết trong khi xem qua danh sách các phần tử có trong danh sách.Lợi tức lợi nhuận trong Java

Làm cách nào để tạo một phiên bản java ở trên nơi tôi có thể lặp qua tất cả các mục có trong danh sách được liên kết?

Tôi đang tìm để có thể viết mã ala

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

Và đã suy nghĩ rằng giá trị 'tài sản'/phương pháp sẽ bao gồm mã giống

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

Edit: Chú ý rằng tôi không quan tâm đến việc sử dụng bất kỳ API của bên thứ ba nào. Chỉ có chức năng java tích hợp.

+0

http: // stackoverflow.com/questions/1980953/is-there-a-java-equivalent-to-cs-yield-keyword –

+2

tôi không biết C#. Tò mò, lợi nhuận thu được sẽ làm gì? – bragboy

+0

kiểm tra điều này: http://msdn.microsoft.com/en-us/library/9k7k7cf0(VS.80).aspx –

Trả lời

-21

Tôi có thiếu gì đó ở đây không? Đã có java.util.LinkedList, nó được kích hoạt hoàn toàn Generics, và nó có một phương thức trả về một Iterator.

Nếu bạn thực sự muốn phát minh lại bánh xe, tôi khuyên bạn nên xem xét việc tạo lớp LinkedListIterator, có thể triển khai ListIterator.Nó sẽ nhớ vị trí hiện tại của nó trong danh sách liên kết và chuyển nó lên từng cuộc gọi liên tiếp.

+2

Lý do tạo cấu trúc dữ liệu của riêng tôi là do nhu cầu mở rộng hiệu năng sau này trong quá trình (có thể không áp dụng nhiều cho danh sách được liên kết như bảng băm). Giải pháp của bạn với một iterator phân lớp là một trong những tôi cuối cùng được sử dụng để giải quyết vấn đề ở bàn tay. –

+22

Tôi nghĩ rằng bạn có thể thiếu một cái gì đó (như là OP). 'yield return' trong C# /. Net chỉ tạo ra một trình lặp. Nếu người tiêu dùng của trình vòng lặp kết thúc sớm, thì vòng lặp tạo ra sự lặp lại cũng vậy. Một máy phát vô hạn là một ví dụ về một cái gì đó mà không thể có mà không có một trình lặp mà không sử dụng một bộ sưu tập như là một bước trung gian. Đối với ví dụ mà họ đưa ra, tất nhiên bạn sẽ chỉ trả về trình lặp từ 'LinkedList'. –

-1

Tôi đã cố gắng để hiểu những gì năng suất làm nhưng mà không có kinh nghiệm C# tôi không chắc chắn nếu tôi có nó, nhưng tôi sẽ cố gắng dù sao ...

tôi xin đề nghị như sau ...

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

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

Khi nói đến việc trả lại giá trị từ một phương pháp i sẽ làm như sau ...

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

Tôi đã mất âm mưu chưa?

+0

bạn đang gọi getAuthors (LinkedList) ở đâu? – bragboy

+0

ummm ... bạn sẽ gọi getAuthors từ bất kỳ đâu trong mã của bạn. nếu bạn tạo một lớp được gọi là Utils (làm ví dụ) và tạo phương thức tĩnh, bạn có thể nói Utils.getAuthors (chuyển danh sách của bạn ở đây); và điều đó sẽ trả về danh sách mới của bạn. – Paul

+4

Tôi trễ nhưng những gì bạn cần hiểu là trong C#, báo cáo trả về lợi nhuận sẽ chỉ được thực hiện sau khi phương thức "MoveNext()" của IEnumerable được gọi. Các mục trong IEnumerable được đánh giá lười biếng như trái ngược với ví dụ của bạn. – GuiSim

-1

Nếu bạn muốn có đầy đủ chức năng của yield return, bạn có thể cần phải thiết lập trong hai chủ đề-- một cho phương thức đầu tiên và một cho lần thứ hai. Sau đó, thread đầu tiên nên wait cho đến khi chuỗi thứ hai đặt giá trị của nó ở một nơi nào đó có thể truy cập và notify s nó đã sẵn sàng. Sau đó, chuỗi đầu tiên sẽ xử lý giá trị đó, wait cho giá trị tiếp theo, v.v.

+0

Tôi nghĩ bạn đã nhầm lẫn chủ đề với http://en.wikipedia.org/wiki/Coroutine – MartinP

4

Tôi không hiểu tại sao mọi người đang nói về chủ đề ... có điều gì tôi không biết về lợi tức không?

Để lợi nhuận hiểu biết của tôi chỉ tiết kiệm ngăn xếp phương thức và khôi phục nó sau này. Để thực hiện trả lại lợi nhuận, bạn chỉ cần lưu trạng thái theo cách thủ công. Xem các lớp Java iterator để biết chi tiết, mặc dù cho một danh sách liên kết bạn chỉ có thể lấy đi với lưu mục hiện tại. Đối với một mảng bạn chỉ cần chỉ mục.

+0

Điều này là chính xác. Lợi nhuận và lợi nhuận không sử dụng chủ đề trong C#. Chúng thực hiện một phép biến đổi thời gian biên dịch và tạo ra một máy trạng thái, nhưng máy trạng thái đó không sử dụng bất kỳ chủ đề phụ nào (mặc dù nó có thể là luồng an toàn). –

1

Chỉ để giúp người đọc hiểu các chi tiết nhỏ.

Nếu bạn tạo danh sách mới chứa tất cả các phần tử kết quả và trả về danh sách, thì đây là một triển khai tốt, đủ đơn giản để viết mã. Bạn có thể có cấu trúc dữ liệu thú vị như bạn cần, và khi quét nó cho các mục phù hợp, chỉ cần trả về một danh sách của tất cả các trận đấu, và khách hàng của bạn sẽ lặp lại trong danh sách.

Nếu bạn muốn lưu trạng thái, điều này có thể phức tạp hơn. Bạn sẽ cần phải đến nơi bạn đã đến mỗi khi chức năng của bạn được gọi. Chưa kể đến các vấn đề tái nhập cảnh, v.v.

Giải pháp với chủ đề không tạo danh sách mới. Và nó đơn giản như giải pháp đầu tiên. Vấn đề duy nhất là bạn liên quan đến một đồng bộ hóa thread đó là một chút khó khăn hơn để mã, và có hình phạt hiệu suất của nó.

Vì vậy, có, thu nhập lợi nhuận rất lớn và bị thiếu từ Java. Tuy nhiên, có cách giải quyết.

30

Bạn có thể trả lại triển khai ẩn danh có thể lặp lại. Các hiệu ứng khá giống nhau, chỉ là điều này có nhiều chi tiết hơn.

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

"thu nhập lợi nhuận" là thủ thuật biên dịch rất phức tạp. Về cơ bản nó cho phép bạn khai báo thực thi IEnumerable mà không có bất kỳ chi tiết gây phiền nhiễu nào của việc "tìm ra" cách xây dựng trình lặp của bạn. Điều đáng tiếc là nó không dịch sang các ngôn ngữ khác tốt bởi vì rất ít trình biên dịch có khả năng như vậy. Trong một số cách "lợi nhuận trở lại" là như damning như cách mạng.

Về cơ bản trong C#, trình biên dịch sẽ tạo ra hai triển khai IEnumerable và IEnumerator (của T). Nó thực hiện điều này bằng cách thực hiện cơ bản các biến cục bộ của phương thức "của bạn" như các trường cá thể trong các lớp thực hiện được tạo ra cũng như kiểm tra các khung chứa một tạo phẩm "trả về lợi nhuận". Một khi bạn biết điều này, nó sẽ là có thể cho một nhà phát triển cũng tròn để thực hiện cùng một điều rõ ràng ... mặc dù không phải là chính xác. Để chứng minh, tôi sẽ 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! 

Nếu tất cả các bạn sẽ tha thứ 3:00 giả java của tôi ...

Các vấn đề liên quan