2012-04-21 19 views
6

Mã của tôi dưới đây tìm tất cả các số nguyên tố bên dưới number bằng cách tạo danh sách số nguyên tố và kiểm tra xem nguyên tố tiềm năng tiếp theo có thể chia đều cho bất kỳ số nguyên tố nào trong danh sách hay không.Bạn có thể truy cập vào IEnumerable khi bạn mang lại lợi nhuận không?

Tôi đang cố gắng tìm hiểu thông tin chi tiết về số yield return. Ngay bây giờ tôi có một List<int> primes mà tôi sử dụng bên trong chức năng. Nhưng tôi trả lại cùng một dữ liệu qua yield return. Vì vậy, câu hỏi của tôi là

Tôi có thể truy cập IEnumerable < int> từ bên trong chức năng như tôi đang tạo không? Vì vậy, tôi có thể xóa toàn bộ danh sách < int.

/// <summary> 
/// Finds all primes below <paramref name="number"/> 
/// </summary> 
/// <param name="number">The number to stop at</param> 
/// <returns>All primes below <paramref name="number"/></returns> 
private static IEnumerable<long> PrimeNumbers(long number) 
{ 
    yield return 2; 
    List<long> primes = new List<long>(2);   

    for(long num = 3; num < number; num += 2) 
    { 

     //if any prime lower then num divides evenly into num, it isn't a prime 
     //what I'm doing now 
     if(!primes.TakeWhile(x => x < num).Any(x => num % x == 0)) 
     { 
      primes.Add(num); 
      yield return num; 
     } 

     //made-up syntax for what I'd like to do 
     if(!this.IEnumerable<long> 
       .TakeWhile(x => x < num).Any(x => num % x == 0)) 
     { 
      yield return num; 
     } 
    } 
} 
+0

Câu trả lời ngắn: Không. Câu trả lời dài: Có nhiều cách tốt hơn để lấy số nguyên tố cho đến một số nhất định. Kiểm tra Sàng của Sundaram: http://en.wikipedia.org/wiki/Sieve_of_Sundaram – SimpleVar

+0

Bạn cũng có thể cải thiện bằng cách đi tìm Sàng Eratosthenes: http://en.wikipedia.org/wiki/Sieve_of_Eratosthenes và thậm chí nhiều hơn bằng cách đi cho Sieve of Atkin: http://en.wikipedia.org/wiki/Sieve_of_Atkin Tôi nghĩ đây là một trong những cách nhanh nhất hiện nay để tạo ra số nguyên tố (nếu không phải là nhanh nhất) và cũng có mã giả trong wiki để giúp bạn nhận được đã bắt đầu. – SimpleVar

+0

@YoryeNathan Tôi thấy những cái rây trên wikipedia và nếu tôi định giữ mã này ở bất cứ nơi nào quan trọng, tôi có thể sử dụng chúng. Mã này giúp ích nhiều hơn cho việc rèn luyện bản thân mình suy nghĩ như thế nào trong tư duy 'lợi nhuận '. –

Trả lời

4

Không, bạn không thể làm điều đó. Trình biên dịch xây dựng một máy trạng thái để thực hiện yield return và mã gọi điện liệt kê thông qua số đếm của bạn là phần lớn hoạt động như mã của bạn. Trình biên dịch xây dựng một đối tượng ẩn lưu trữ trạng thái hiện tại của mã của bạn, bao gồm ngăn xếp cuộc gọi và người dân địa phương và gọi các phần khác nhau của phương thức của bạn khi người gọi gọi CurrentMoveNext. Cố gắng liệt kê đối tượng của bạn ngay từ đầu trong khi một liệt kê khác đang được tiến hành sẽ làm rối loạn việc liệt kê đang diễn ra, điều đó sẽ không tốt. Trong trường hợp cụ thể này, bạn không muốn điều đó xảy ra: việc triển khai yield return không lưu trữ các giá trị bạn sản xuất, vì vậy nếu ngay cả khi bạn có thể truy cập vào số IEnumerable của riêng mình trong khi liệt kê, nó sẽ gọi lại một cách đệ quy chính nó nhiều lần để sản xuất mỗi mục mới, do đó, nó sẽ đưa bạn ridiculously dài thời gian để sản xuất ngay cả một số lượng vừa phải của số nguyên tố.

+0

Tất nhiên bạn có thể. Đếm ngược hoặc lồng nhau liệt kê được cho là sẽ được xử lý tự động, đó là một phần của vẻ đẹp của chúng. Điều này sẽ làm điều đó: 'if (! PrimeNumbers (num). Bất kỳ (x => num% x == 0)) trả về num'. Chỉ cần thử nghiệm trong LINQPad. Tuy nhiên, điểm thứ hai của bạn là viết tắt, rằng nó vô cùng khủng khiếp. Bạn có thể nói điều này bằng cách thực hiện một 'Console.WriteLine (..)' bên trong hàm để xem có bao nhiêu lần nó liệt kê cùng một kết quả. – mellamokb

+1

@mellamokb Đó là không truy cập * chính nó * từ chức năng tạo chuỗi. Nó đang truy cập * một bản sao giống hệt nhau * của chính nó, với trạng thái riêng của nó, máy trạng thái và mọi thứ khác. Đó là lý do tại sao nó không phá vỡ, và đó là lý do tại sao nó rất chậm :) – dasblinkenlight

+0

Ah! Tôi đang ở trên cùng một trang bây giờ :) Có, bạn không thể lấy các mục trước đó từ cùng một trường hợp vì trạng thái trước đó không còn tồn tại nữa. – mellamokb

2

Tổng số điều tra không phải là vùng chứa như List<int> primes. Nó là một "quá trình" để tìm số nguyên tố. Nếu bạn đệ quy sử dụng quy trình của riêng bạn để tạo danh sách các số nguyên tố để chống lại việc tìm kiếm số nguyên tố tiếp theo, bạn sẽ đệ quy đệ quy các kết quả tương tự lặp đi lặp lại sẽ vô cùng không hiệu quả. Xem xét những gì sẽ xảy ra (nếu bạn thực sự có thể làm được điều này) cho việc tìm kiếm các số nguyên tố lên đến 10.

yield return 2 
num = 3 
IEnumerable<long>.TakeWhile(x => x < 3).Any(x => num % x == 0) 
    new enumerator 
    yield return 2 
yield return 3 
num = 4 
IEnumerable<long>.TakeWhile(x => x < 4).Any(x => num % x == 0) 
    new enumerator 
    yield return 2 
    num = 3 
    IEnumerable<long>.TakeWhile(x => x < 3).Any(x => num % x == 0) 
     new enumerator 
     yield return 2 
    yield return 3 
num = 5 
IEnumerable<long>.TakeWhile(x => x < 5).Any(x => num % x == 0) 
    new enumerator 
    yield return 2 
    num = 3 
    IEnumerable<long>.TakeWhile(x => x < 4).Any(x => num % x == 0) 
     new enumerator 
     yield return 2 
     num = 3 
     IEnumerable<long>.TakeWhile(x => x < 3).Any(x => num % x == 0) 
      new enumerator 
      yield return 2 
     yield return 3 
     num = 4 
etc. 

Đây là một enumartion tăng theo cấp số nhân. Nó giống như việc tìm kiếm số lượng mã vạch bằng cách tính toán f(n-1) + f(n-2). Bạn đang làm rất nhiều công việc tương tự hơn và hơn nữa, và thậm chí nhiều hơn để bạn đạt đến con số cao hơn. Danh sách các số nguyên tố nội bộ đóng vai trò như một loại bộ nhớ cache để làm cho việc liệt kê của bạn rất hiệu quả.

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