2016-02-22 10 views
5

मान लीजिए (धनात्मक पूर्णांक मेरी दृश्यों सभी आरोही क्रम में सॉर्ट कर रहे हैं, और होते हैं) मैं निम्नलिखित सरणी हैLINQ क्वेरी एक श्रृंखला में टुकड़े की पहचान करने के

var mySequence = new [] {1, 2, 3, 7, 8, 9, 15, 16, 17}; 

मैं निरंतर चयन करने के लिए एक LINQ क्वेरी लिखना चाहते हैं एक समूह के रूप में इलाज श्रृंखला में संख्या। तो, उपर्युक्त उदाहरण में मुझे {[1, 2, 3], [7, 8, 9], [15, 16, 17]} मिलेगा।

मैं foreach() अनुक्रम लिख सकता हूं, प्रत्येक तत्व के माध्यम से चला सकता हूं और देख सकता हूं कि अनुक्रम एक हॉप ले रहा है और वहां एक समूह उत्पन्न करता है। लेकिन क्या ऐसा करने का कोई LINQ-only तरीका है? मैं अपने foreach() कोड को एक नई एक्सटेंशन विधि में स्थानांतरित करने में सक्षम हो सकता हूं, इसलिए मेरा कोड अभी भी LINQy दिखता है, लेकिन मुझे आश्चर्य है कि सिस्टम में कुछ भी उपलब्ध है। लिनक पहले से ही इसके लिए।

संपादित करें: मैंने अपना स्वयं का विस्तार (निम्नानुसार) बनाया है, लेकिन Me.Name उसके उत्तर में कुछ बहुत स्मार्ट के साथ आया था।

internal class Sequence 
{ 
    public int Start { get; set; } 
    public int End { get; set; } 
} 

internal static class EnumerableMixins 
{ 
    public static IEnumerable<Sequence> GroupFragments(this IEnumerable<int> sequence) 
    { 
     if (sequence.Any()) 
     { 
      var lastNumber = sequence.First(); 
      var firstNumber = lastNumber; 

      foreach(var number in sequence.Skip(1)) 
      { 
       if (Math.Abs(number - lastNumber) > 1) 
       { 
        yield return new Sequence() { Start = firstNumber, End = lastNumber }; 

        firstNumber = lastNumber = number; 
       } 
       else 
       { 
        lastNumber = number; 
       } 
      } 


      yield return new Sequence() { Start = firstNumber, End = lastNumber }; 
     } 
    } 
} 

उत्तर

10

इस तरह के द्वीपों को खोजने के लिए एक पुरानी चाल इंडेक्स और संख्यात्मक मूल्य घटाना है। नतीजा अद्वितीय समूहों का प्रतिनिधित्व करेगा। (यहाँ प्रयुक्त ToList, लेकिन निश्चित रूप से toArray सरणियों को प्राथमिकता दी जाती है, तो इस्तेमाल किया जा सकता)

var mySequence = new [] {1, 2, 3, 7, 8, 9, 15, 16, 17}; 

var groups = mySequence 
    .Select((val,ind) => new{val, group = val - ind}) 
    .GroupBy(v=>v.group, v=>v.val) 
    .Select(v=> v.ToList()).ToList(); 

+0

यह integers-- के लिए एक प्यारा चाल है यदि का परिणाम (संख्या - इंडेक्स) 0 है तो यह संख्या अपेक्षित सरणी स्थान पर है, यदि संख्या ऋणात्मक है तो यह अपेक्षा की जाती है कि इसकी अपेक्षा कहीं अधिक हो। – Hogan

+0

क्या होगा यदि मेरा अनुक्रम 1 से शुरू नहीं होता है? मान लीजिए यह मेरी श्रृंखला var x = new [] {20, 21, 22, 25,26,27, 30,31,32} है; – fahadash

+1

@fahadash: यह भी काम करेगा, इरादा यह है कि मूल्यों के बीच अंतर होने पर सूचकांक और मूल्य के बीच का अंतर अधिक होता है। उस अनुक्रम के लिए: 20-0 = 20, 21-1 = 20, 22 -2 = 20, 25 -3 = 22, 26-4 = 22, आदि। तो 'समूह' मान 20 से 22 –

1

मैं थोड़ा देर से लेकिन वैसे भी मैं विचार साझा करना चाहते हैं: सूचकांक सहित चुनिंदा अधिभार का उपयोग करना। आप भी इस तरह एक इटरेटर बना सकते हैं:

public static class Extensions 
{ 
    public static IEnumerable<IEnumerable<int>> ContinuousNumbers(this IEnumerable<int> source) 
    { 
     using (var e = source.GetEnumerator()) 
     { 
      if (e.MoveNext()) 
      { 
       var list = new List<int> { e.Current}; 
       int temp = e.Current; 
       while (e.MoveNext()) 
       { 
        if (e.Current == temp+1) 
        { 
         list.Add(e.Current); 
         temp++; 
        } 
        else 
        { 
         yield return list; 
         list = new List<int> { e.Current}; 
         temp = e.Current; 
        } 
       } 

       if (list.Count > 0) 
       { 
        yield return list; 
       } 
      } 
     } 
    } 
} 

एक और प्रकार Aggregate विस्तार विधि का उपयोग किया जा सकता है:

var result = mySequence.Aggregate(new List<List<int>>(), 
            (r, current) => 
            { 
             if (r.Count==0 || (r.Last().Count>0 && r.Last().Last() != current-1)) 
              r.Add(new List<int> { current}); 
             else 
              r.Last().Add(current); 
             return r; 
            }); 
संबंधित मुद्दे