2012-04-21 38 views
6

नीचे दिए गए मेरे कोड में प्राइम की एक सूची बनाकर number से नीचे सभी प्राइम संख्याएं मिलती हैं और यह देखने के लिए जांच की जाती है कि अगला संभावित प्राइम सूची में किसी भी प्राइम द्वारा समान रूप से विभाजित है या नहीं।क्या आप IENumerable तक पहुंच सकते हैं क्योंकि आप इसे लौट रहे हैं?

मैं yield return के इंस और आउट सीखने की कोशिश कर रहा हूं। अभी मेरे पास List<int> primes है जो मैं फ़ंक्शन के अंदर उपयोग करता हूं। लेकिन मैं उसी डेटा को yield return के माध्यम से वापस कर रहा हूं। तो मेरा सवाल

क्या मैं इसे बनाने के रूप में फ़ंक्शन के अंदर से IENumerable < int> तक पहुंच सकता हूं? तो मैं सूची < int> primes पूरी तरह से हटा सकते हैं।

/// <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

संक्षिप्त उत्तर: नहीं। लंबा उत्तर: एक निश्चित संख्या तक प्राइम प्राप्त करने के बेहतर तरीके हैं। सुंदरम की छलनी देखें: http://en.wikipedia.org/wiki/Sieve_of_Sundaram – SimpleVar

+0

आप इरेटोस्टेनेस की चलनी के लिए जाकर भी सुधार कर सकते हैं: http://en.wikipedia.org/wiki/Sieve_of_Eratosthenes और यहां तक ​​कि और भी जाकर एटकिन की चलनी: http://en.wikipedia.org/wiki/Sieve_of_Atkin जो मुझे लगता है कि आज सबसे तेज़ तरीकों में से एक है जिसे प्रमुख संख्याएं उत्पन्न करने के लिए जाना जाता है (यदि सबसे तेज़ नहीं है) और विकी में छद्म कोड भी आपको प्राप्त करने में मदद करता है शुरू कर दिया है। – SimpleVar

+0

@YoryeNathan मैंने उन चाकू को विकिपीडिया पर देखा और यदि मैं इस कोड को कहीं भी महत्वपूर्ण रखने जा रहा था तो शायद मैं उनका उपयोग करूंगा। यह कोड 'उपज रिटर्न' मानसिकता में सोचने के तरीके को प्रशिक्षित करने में मदद करने के लिए और अधिक था। –

उत्तर

4

नहीं, आप ऐसा नहीं कर सकते। कंपाइलर yield return को लागू करने के लिए एक राज्य मशीन बनाता है, और आपके कोड के अनुसार गणना करने वाला कॉलिंग कोड आपके कोड के रूप में काम करने का एक हिस्सा है। कंपाइलर एक छुपे ऑब्जेक्ट बनाता है जो आपके कोड की वर्तमान स्थिति को स्टोर करता है, जिसमें कॉल कॉल और स्थानीय शामिल हैं, और यह आपकी विधि के विभिन्न टुकड़ों को कॉल करता है क्योंकि कॉलर Current और MoveNext को आमंत्रित करता है। शुरुआत से ही अपनी वस्तु का आकलन करने की कोशिश करते हुए एक और गणना प्रगति पर चल रही है, जो चल रही गणना को गड़बड़ कर देगी, जो अच्छा नहीं होगा।

इस विशेष मामले में, आप यह तो होना ही या तो नहीं करना चाहती: इसलिए यदि भले ही आप को एन्यूमेरेट करते हुए अपने खुद के IEnumerable यहां पहुंच सकता है yield return के कार्यान्वयन, मूल्यों है कि आप उत्पादन की दुकान नहीं है, यह रिकर्सिवली वापस बुलाना होगा प्रत्येक नई वस्तु का उत्पादन करने के लिए खुद को कई बार, इसलिए यह आपको हास्यास्पद रूप से लंबे समय तक प्राइम का उत्पादन करने के लिए लंबे समय तक ले जाएगा।

+0

बेशक आप कर सकते हैं। रिकर्सिव या नेस्टेड एन्युमरेशन स्वचालित रूप से संभाले जाने वाले हैं, जो उनकी सुंदरता का हिस्सा हैं। यह ऐसा करेगा: 'अगर (! प्राइम नब्स (अंक)। कोई (x => num% x == 0)) उपज वापसी संख्या'। LINQPad में बस परीक्षण किया गया। हालांकि आपका दूसरा बिंदु खड़ा है, कि यह बेहद अक्षम है। आप यह देखने के लिए कि केवल एक ही परिणाम की गणना करने के लिए कितनी बार यह देखने के लिए फ़ंक्शन के अंदर 'कंसोल। राइटलाइन (..)' कर कर इसे बता सकते हैं। – mellamokb

+1

@mellamokb यह उस अनुक्रम से * स्वयं * तक पहुंच नहीं रहा है जो अनुक्रम बनाता है। यह अपने स्वयं के राज्य, राज्य मशीन, और बाकी सब कुछ के साथ * एक समान प्रति * का उपयोग कर रहा है। यही कारण है कि यह तोड़ नहीं है, और यही कारण है कि यह बहुत धीमी है :) – dasblinkenlight

+0

आह! मैं अब एक ही पृष्ठ पर हूं :) हां, आप एक ही उदाहरण से पिछली प्रविष्टियों पर नहीं पकड़ सकते हैं क्योंकि पिछला राज्य अब मौजूद नहीं है। – mellamokb

2

समग्र गणनाकर्ता List<int> primes जैसा कंटेनर नहीं है। यह primes खोजने के लिए एक "प्रक्रिया" है। यदि आप अगले प्राइम को खोजने के लिए काम करने के लिए प्राइम्स की सूची उत्पन्न करने के लिए अपनी प्रक्रिया का पुन: उपयोग करते हैं, तो आप बार-बार वही परिणाम बताएंगे जो बेहद अक्षम होंगे। विचार करें कि ऊपर 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. 

यह एक तेजी से बढ़ enumartion है को अभाज्य संख्या को खोजने के लिए होगा (यदि आप वास्तव में ऐसा कर सकता है)। यह f(n-1) + f(n-2) की गणना करके मूर्खतापूर्ण फाइबोनैकी संख्याओं को खोजने के समान है। आप एक ही काम को बार-बार कर रहे हैं, और इससे भी ज्यादा जैसे आप उच्च संख्या तक पहुंचते हैं। प्राइम की आंतरिक सूची आपके गणित को बहुत ही कुशल बनाने के लिए कैश के रूप में कार्य करती है।