2010-09-02 5 views
7

मैं की तरह एक वर्ग है:क्या यह संभव है लिखने के लिए एक पुनरावर्ती IEnumerable <T>

class Spline 
    int ChildrenCount; 
    Spline GetChild (int index) 

class SplineCollection : IEnumerable<Spline> 
    Spline Master 

यह SplineCollection जहां यह सभी बच्चों को एक के बाद एक वापस आ जाएगी के लिए एक पुनरावर्ती IEnumerable लिखने के लिए संभव है?

संपादित करें: तो मास्टर रूट बॉक्स है, और इसके बच्चों का पदानुक्रम कोई गहराई हो सकता है।

संपादित करें: नाम बॉक्स का उपयोग करके, मुझे लगता है कि मैंने कुछ लोगों को भ्रमित कर दिया। यह एक ज्यामितीय वस्तु है, एक कंटेनर नहीं है। तो इसे स्पलीन में बदल रहा है।

+1

जब आप बच्चों को लिखते हैं तो मुझे इसका मतलब है "वंशज", क्योंकि बच्चों को कोई रिकर्सन की आवश्यकता नहीं होती है। –

+0

@ जॉब, हाँ आप सही हैं मैं वंशजों का मतलब था। यह सिर्फ इतना है कि मैं जिस एसडीके का उपयोग कर रहा हूं, उन्हें अभी भी बच्चों, बच्चों के रूप में जाना जाता है, इसलिए मैंने इसका उपयोग किया। –

उत्तर

9

यह Box 'पेड़' का गहराई से पहला ट्रैवर्सल करेगा। इसके बाद आप सभी पुनरावर्ती बच्चों को वापस करने के लिए Master बॉक्स पर इस विधि को कॉल कर सकते हैं।

public class Box 
{ 
    // ... 

    public IEnumerable<Box> GetBoxes() 
    { 
     yield return this; 

     for (int i=0; i<box.ChildrenCount; i++) 
     { 
      foreach (Box child in box.GetChild(i).GetBoxes()) 
      { 
       yield return child; 
      } 
     } 
    } 
} 
+0

धन्यवाद लेकिन क्या यह प्रत्येक बॉक्स के बच्चों के माध्यम से जाएगा। GetChild (i) भी? –

+0

आह, अब यह समझ में आता है। जवाब संपादित किया। – thecoop

3

हाँ - सी # iterators का उपयोग कर Recursive Iterations के लिए इस खंड को देखें।

1
class Box 
{ 
    int ChildrenCount; 
    Box GetChild (int index){/* some implementation*/} 
    public IEnumerable<Box> Children 
    { 
    get 
    { 
     for(int i = 0; i != ChildrenCount; ++i) 
     yield return GetChild(i); 
    } 
    } 
    public IEnumerable<Box> Descendants 
    { 
    get 
    { 
     foreach(Box child in Children) 
     { 
     yield return child; 
     foreach(Box desc in child.Descendants) 
      yield return desc; 
     } 
    } 
    } 
} 

आप BoxCollection से कॉल कर सकते हैं, लेकिन जब से बॉक्स पहले से ही बक्से का एक संग्रह है, मैं नहीं दिख रहा है क्या BoxCollection का उद्देश्य यहाँ है। उस मामले के लिए, बॉक्स को लागू करना IEnumerable<Box> या इसके वंशजों में से एक (ICollection<Box>, IList<Box>) शायद उपयोगिता में सुधार करेगा।

रिकर्सिव तरीके से इसे पुनरावर्तक तरीके से करना भी संभव है, जो कभी-कभी बेहतर प्रदर्शन करता है (जब भी कंपाइलर किसी भी तरह से घुसपैठ में घुसपैठ नहीं करता है), लेकिन रिकर्सिव अधिक सामान्य और सामान्य है पर्याप्त प्रदर्शन करने से अधिक।

-1

निश्चित रूप से।

public class Box 
{ 
    private List<Box> myBoxes; 

    public IEnumerable<Box> GetAllBoxes() 
    { 
     yield return this; 
     foreach (var box in myBoxes) 
     { 
      var enumerator = box.GetAllBoxes().GetEnumerator(); 
      while(enumerator.MoveNext()) 
       yield return enumerator.Current; 
     } 
    } 
} 

बॉक्स एक आयोजित तो बक्से बी और सी, बॉक्स बी बक्से डी और ई, और बॉक्स सी आयोजित आयोजित: आप भी नहीं वास्तव में जरूरत है एक BoxContainer, बॉक्स के बाद से, अपने नाम से, एक कंटेनर के रूप में मौजूद है बॉक्स एफ, संख्यात्मक ए, बी, डी, ई, सी, एफ

+0

आपका 'foreach' प्रभावी रूप से' IENumerable > 'के रिटर्न प्रकार में परिणाम देता है जो घोषित रिटर्न प्रकार से मेल नहीं खाता है। मुझे विश्वास नहीं है कि यह सी # में संकलित होगा। एफ # में आप दूसरे 'उपज' को 'उपज' में बदल सकते हैं और यह ठीक काम करेगा। –

+0

आप बिल्कुल सही हैं।बाल बॉक्स द्वारा लौटाए गए आईन्यूमेरेबल के माध्यम से फिर से शुरू करने के लिए त्वरित संपादन। – KeithS

1

हां, लेकिन आपको रिकर्सिव परिणाम का आकलन करना होगा। आप इसे वापस नहीं कर सकते हैं, क्योंकि प्रकार मेल नहीं खाता है।

IEnumerable<int> Triangle(int n) { 
    yield return n; 
    if (n > 0) 
     foreach (var e in Triangle(n - 1)) 
      yield return e; 
} 
10

मैं यहां कॉल स्टैक पर भरोसा करने के बजाय मैन्युअल रूप से एक स्टैक बनाए रखने के साथ जाऊंगा। इसका कारण यह है कि प्रत्येक प्रत्येक Spline के लिए बनाया जाना होगा यदि आप कॉल स्टैक का इस्तेमाल बार-बार प्राप्त करने वाली विधि को कॉल करके करते हैं। वह अक्षम होगा। आप अपने स्वयं के ढेर का उपयोग कर ट्रैवर्सल में काफी सुधार कर सकते हैं।

public IEnumerable<Spline> Descendants 
{ 
    get 
    { 
     // This performs a simple iterative preorder traversal. 
     var stack = new Stack<Spline>(new Spline[] { this }); 
     while (stack.Count > 0) 
     { 
      Spline current = stack.Pop(); 
      yield return current; 
      for (int i = current.ChildrenCount - 1; i >= 0; i--) 
      { 
       stack.Push(current.GetChild(i)); 
      } 
     } 
    } 
} 
+2

मेरी इच्छा है कि मैं इसे 10 बार वोट दे सकता हूं। यह एक पुनरावर्ती समाधान की तुलना में * अधिक * अधिक कुशल है, और केवल कुछ सेकंड और विचार की आवश्यकता है। वास्तव में, आप किसी भी पुनरावर्ती इटरेटर को सरल बनाने के लिए इसे 'फ़्लैटन' फ़ंक्शन में सामान्यीकृत कर सकते हैं। –

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