2010-04-24 14 views
9

विफल रहा है मैं linq का उपयोग कर सी # का उपयोग कर एक कार्यात्मक शैली में quicksort लागू करने की कोशिश कर रहा हूँ, और यह कोड यादृच्छिक रूप से काम करता है/काम नहीं करता है, और मैं समझ नहीं सकता क्यों।
उल्लेख करने के लिए महत्वपूर्ण: जब मैं इसे किसी सरणी या सूची पर कॉल करता हूं, तो यह ठीक काम करता है। लेकिन पर एक अज्ञात-क्या यह वास्तव में-है IEnumerable, यह पागल (मान या दुर्घटनाओं, आम तौर पर कभी कभी काम करता है खो देता है।।) चला जाता है
कोड:सी # कार्यात्मक Quicksort

public static IEnumerable<T> Quicksort<T>(this IEnumerable<T> source) 
     where T : IComparable<T> 
    { 
     if (!source.Any()) 
      yield break; 
     var pivot = source.First(); 
     var sortedQuery = source.Skip(1).Where(a => a.CompareTo(source.First()) <= 0).Quicksort() 
          .Concat(new[] { pivot }) 
          .Concat(source.Skip(1).Where(a => a.CompareTo(source.First()) > 0).Quicksort()); 
     foreach (T key in sortedQuery) 
      yield return key; 
    } 

आप किसी भी दोष मिल सकता है यहां इससे असफल होने का कारण होगा?

संपादित करें: कुछ बेहतर परीक्षण कोड:

 var rand = new Random(); 
     var ienum = Enumerable.Range(1, 100).Select(a => rand.Next()); 
     var array = ienum.ToArray(); 
     try 
     { 
      array.Quicksort().Count(); 
      Console.WriteLine("Array went fine."); 
     } 
     catch (Exception ex) 
     { 
      Console.WriteLine("Array did not go fine ({0}).", ex.Message); 
     } 
     try 
     { 
      ienum.Quicksort().Count(); 
      Console.WriteLine("IEnumerable went fine."); 
     } 
     catch (Exception ex) 
     { 
      Console.WriteLine("IEnumerable did not go fine ({0}).", ex.Message); 
     } 
+1

आपका क्या मतलब है 'अज्ञात-क्या-वास्तव में- IENumerable' है ?? यह एक सामान्य विधि है, इसलिए आपके ऑब्जेक्ट के प्रकार हमेशा ज्ञात होते हैं। –

+0

मेरा मतलब है कि मुझे नहीं पता कि IENumerable खोल के नीचे क्या है। क्या यह एक सूची है? एक सरणी? मैंने जो कोशिश की और एक सूची से क्या असफल रहा, जहां मैंने मूल रूप से "रैंडम रैंड = ...; int [100] किया। चयन करें (ए => rand.Next());" – Rubys

उत्तर

7

ऐसे एसक्यूएल या इकाई की रूपरेखा प्रश्नों का Linq से लौटे उन जैसे कुछ गणनीय उदाहरणों, केवल एक बार दोहराया जा करने के लिए डिजाइन किए हैं। आपके कोड को कई पुनरावृत्तियों की आवश्यकता है और इन प्रकार के उदाहरणों पर अजीब तरह से दुर्घटनाग्रस्त या व्यवहार करेंगे। आपको उन संख्याओं को ToArray() या पहले एक समान विधि के साथ पूरा करना होगा।

आपको भी pivot का पुन: उपयोग करना चाहिए ताकि आपको पहले और शेष तत्वों के लिए पुनरावृत्ति को रखने की आवश्यकता न हो। यह पूरी तरह से समस्या का समाधान नहीं हो सकता है, लेकिन यह कुछ मामलों में आपकी सहायता करेंगे: (। तुम भी sortedQuery के माध्यम से पुनरावृति की जरूरत नहीं है - बस इसे वापस, यह पहले से ही एक IEnumerable<T> है)

public static IEnumerable<T> Quicksort<T>(this IEnumerable<T> source) 
    where T : IComparable<T> 
{ 
    if (!source.Any()) 
     return source; 
    var pivot = source.First(); 
    var remaining = source.Skip(1); 
    return remaining 
     .Where(a => a.CompareTo(pivot) <= 0).Quicksort() 
     .Concat(new[] { pivot }) 
     .Concat(remaining.Where(a => a.CompareTo(pivot) > 0).Quicksort()); 
} 

संबंधित नोट पर, आपको इस कार्यक्षमता को फिर से कार्यान्वित करने की आवश्यकता क्यों महसूस होती है? Enumerable.OrderBy पहले से ही आपके लिए यह करता है।


रिस्पांस अद्यतन करने के लिए:

आपका परीक्षण असफल रहे हैं क्योंकि अपने परीक्षण गलत, नहीं एल्गोरिथ्म है।

Random एक गैर-निर्धारिती इनपुट स्रोत है और जैसा कि मैंने उपरोक्त समझाया है, सॉर्ट विधि को उसी अनुक्रम पर एकाधिक पुनरावृत्तियों को करने की आवश्यकता है। अगर अनुक्रम पूरी तरह यादृच्छिक है, तो इसे बाद के पुनरावृत्तियों पर अलग-अलग मान मिलेंगे। अनिवार्य रूप से, आप एक अनुक्रम को त्वरित रूप से करने की कोशिश कर रहे हैं जिनके तत्व बदलते रहते हैं!

यदि आप परीक्षण सफल होना चाहते हैं, तो आपको इनपुट संगत इनपुट करने की आवश्यकता है। यादृच्छिक संख्या जनरेटर के लिए एक बीज का उपयोग करें:

static IEnumerable<int> GetRandomInput(int seed, int length) 
{ 
    Random rand = new Random(seed); 
    for (int i = 0; i < length; i++) 
    { 
     yield return rand.Next(); 
    } 
} 

तब:

static void Main(string[] args) 
{ 
    var sequence = GetRandomInput(248917, 100); 
    int lastNum = 0; 
    bool isSorted = true; 
    foreach (int num in sequence.Quicksort()) 
    { 
     if (num < lastNum) 
     { 
      isSorted = false; 
      break; 
     } 
     lastNum = num; 
    } 
    Console.WriteLine(isSorted ? "Sorted" : "Not sorted"); 
    Console.ReadLine(); 
} 

यह वापस आ जाएगा अनुसार क्रमबद्ध।

+0

मेरा गणितीय वास्तव में केवल संख्यात्मक था। श्रेणी, और यह अभी भी असफल रहा। इसके अलावा, मैंने बस sortedQuery को वापस करने का प्रयास किया, लेकिन मुझे एक त्रुटि मिली - "एक इटरेटर से मूल्य वापस नहीं कर सकता। मूल्य वापस करने के लिए उपज वापसी विवरण का उपयोग करें, या पुनरावृत्ति को समाप्त करने के लिए उपज ब्रेक का उपयोग करें।" और - और - मुझे इसे कार्यान्वित करने की आवश्यकता नहीं है, मैं बस कार्यात्मक प्रोग्रामिंग सीखने की कोशिश कर रहा हूं। – Rubys

+0

@Rubys: आप "मूल्य वापस नहीं कर सकते" त्रुटि के बारे में सही हैं - मैंने बस इसे ठीक किया है, उस समस्या में शुरुआत में 'उपज ब्रेक' था जो अंत में प्रत्यक्ष वापसी के साथ मिश्रित किया जा रहा था। मैं इसे 'एन्यूमेरेबल। रेंज' के साथ आज़माउंगा और देखें कि क्या होता है। – Aaronaught

+0

@Rubys: यहां 'संख्यात्मक। श्रेणी' पर बिल्कुल ठीक काम करता है। असफल होने वाला अपना टेस्ट कोड पोस्ट करें। – Aaronaught

संबंधित मुद्दे