2011-12-01 12 views
6

मैंने संग्रह में लगातार मूल्यों की संख्या को खोजने के लिए एक विस्तार विधि बनाई है। चूंकि यह सामान्य है, इसलिए मैं कॉलर को "incrementor" को परिभाषित करने की अनुमति देता हूं जो एक Func <> है जो "अगले" मान के अस्तित्व की जांच के लिए मान को बढ़ाने के लिए माना जाता है।मैं एक कस्टम गणक के साथ अनंत रिकर्सन से कैसे बचूं?

हालांकि, फोन करने वाले एक अनुचित incrementor गुजरता है अगर (अर्थात एक्स => x), यह एक अनंत पुनरावर्ती पाश का कारण होगा। इसे रोकने के लिए एक साफ तरीके से कोई सुझाव?

public static int CountConsecutive<T>(this IEnumerable<T> values, T startValue, Func<T, T> incrementor) 
{ 
    if (values == null) 
    { 
     throw new ArgumentNullException("values"); 
    } 
    if (incrementor == null) 
    { 
     throw new ArgumentNullException("incrementor"); 
    } 
    var nextValue = incrementor(startValue); 
    return values.Contains(nextValue) 
     ? values.CountConsecutive(nextValue, incrementor) + 1 
     : 1; 
} 
+2

सरल समाधान यह मानना ​​है कि कॉलर लिखने वाला व्यक्ति सचेत है। कभी-कभी आपको अपने ऊपर वाले व्यक्ति को दोष देना पड़ता है। हालांकि, यह एक दिलचस्प सवाल है, इसलिए मैं देखना चाहता हूं कि अन्य लोग टेबल पर क्या ला सकते हैं। – Polynomial

+1

[समस्या निवारण] (http://en.wikipedia.org/wiki/Halting_problem)? –

+0

यदि आपका आईन्यूमेरेबल बड़ा और संगत (दिया गया incrementor) है, तो यह StackOverflowExceptions के लिए अतिसंवेदनशील है। –

उत्तर

0

शुद्धतम अर्थ में, यह Halting Problem पर एक प्रयास है और अनिर्णनीय है। सबसे सरल मामलों के लिए, आपको अपनी विधि को कॉल करने वाले लोगों पर भरोसा करना होगा।

की तरह दूसरों से पता चला है, तो आप को दिखाने के लिए है कि अगले मान भिन्न है समानता का एक सरल जांच कर सकते हैं। प्रत्येक विज़िट किए गए T को संग्रहीत करना काम करेगा, लेकिन आपको स्मृति अंततः मेमोरी के बारे में चिंता करनी होगी।

एक के रूप में अलग रूप में, यहाँ एक आसानी से लागू किया StackOverflowException है तो आप किसी भी डेटा सेट कि लगातार मूल्यों पर बहुत कुछ करना होगा से सावधान रहना होगा।

var x = Enumerable.Range(1, 100000).CountConsecutive(1, x => x+1); 
+0

रिकर्स की गहराई के कारण स्टैक ओवरफ़्लो है? –

+0

हां। उदाहरण में, वे लगातार 'x => x + 1' दिए गए हैं और यह लगभग 77K (मेरी मशीन पर) बह जाएगा। –

1

आप startValue को nextValue तुलना कर सकते हैं (आप IComparable लागू करने के लिए टी की आवश्यकता होगी)।

यह इस बग का समाधान होगा, यह एक बुरा incrementor बग कि एक पाश रिटर्न का समाधान नहीं होगा - A1, A2, A3, ..., एक, A1। मुझे नहीं लगता कि आप को संभालने के लिए इस मामले चाहते हैं, हालांकि

+1

कोई जरूरत IComparable लागू करने के लिए - आप सभी की जरूरत समानता –

4

सबसे सामान्य स्थिति से निपटने के लिए, आप यह कर सकते हैं:

var nextValue = incrementor(startValue); 
if (nextValue.Equals(startValue)) { 
    throw new ArgumentException("incrementor"); 
} 

सामान्य मामले के लिए, इस कार्य करें:

public static int CountConsecutive<T>(this IEnumerable<T> values, T startValue, Func<T, T> incrementor) { 
    if (values == null) { 
     throw new ArgumentNullException("values"); 
    } 
    if (incrementor == null) { 
     throw new ArgumentNullException("incrementor"); 
    } 
    ISet<T> seen = new HashSet<T>(); 
    return CountConsecutive(values, startValue, incrementor, seen); 
} 

private static int CountConsecutive<T>(IEnumerable<T> values, T startValue, Func<T, T> incrementor, ISet<T> seen) { 
    if (!seen.Add(startValue)) { 
     throw new ArgumentException("incrementor"); 
    } 
    var nextValue = incrementor(startValue); 
    return values.Contains(nextValue) 
     ? values.CountConsecutive(nextValue, incrementor) + 1 
     : 1; 
} 
+1

+1 है: यह देखते हुए कि incrementor समारोह के रूप में परिभाषित किया गया है, यह शायद ही मतलब होता अगर यह एक ही मान दिया। बेशक यह किसी प्रकार की स्थैतिक आंतरिक कॉल गिनती नहीं रखता है और इसे 1,1,2,2,3,3 की तरह कुछ वापस करने के लिए बनाया जाता है, लेकिन अगर मुझे इस तरह के वेतन वृद्धि की आवश्यकता होती है तो मुझे आश्चर्य होगा। ऐसा लगता है कि incrementor (x)! = X और इसके लिए भी विश्वकोश होना आवश्यक है। –

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