2012-01-05 55 views
3

例如,我有一個類象下面這樣:Linq如何實現它?

public class SampleItem 
{ 
    public string QCD { get; set; } 
    public string CCD { get; set; } 
    public string ITYPE { get; set; } 
} 

然後,我有一個列表:

var lstTest = new List<SampleItem>() { 

    new SampleItem(){ QCD = "Q1" , CCD = "C1" , ITYPE = "A"} , 
    new SampleItem(){ QCD = "Q1" , CCD = "C2" , ITYPE = "A"} , 
    new SampleItem(){ QCD = "Q1" , CCD = "C3" , ITYPE = "A"} , 

    new SampleItem(){ QCD = "Q1" , CCD = "C1" , ITYPE = "B"} , 
    new SampleItem(){ QCD = "Q1" , CCD = "C2" , ITYPE = "B"} , 
}; 

我想2組像

組1:

new SampleItem(){ QCD = "Q1" , CCD = "C1" , ITYPE = "A"} , 
new SampleItem(){ QCD = "Q1" , CCD = "C2" , ITYPE = "A"} , 
new SampleItem(){ QCD = "Q1" , CCD = "C3" , ITYPE = "A"} , 

組2:

new SampleItem(){ QCD = "Q1" , CCD = "C1" , ITYPE = "B"} , 
new SampleItem(){ QCD = "Q1" , CCD = "C2" , ITYPE = "B"} , 

所以,我只需要

lstTest.GroupBy (p=>new {p.QCD ,p.ITYPE}); 

但現在,如果我的列表的順序是像下面

var lstTest = new List<SampleItem>() { 

    new SampleItem(){ QCD = "Q1" , CCD = "C1" , ITYPE = "B"} , 
    new SampleItem(){ QCD = "Q1" , CCD = "C2" , ITYPE = "B"} , 

    new SampleItem(){ QCD = "Q1" , CCD = "C1" , ITYPE = "A"} , 
    new SampleItem(){ QCD = "Q1" , CCD = "C2" , ITYPE = "A"} , 
    new SampleItem(){ QCD = "Q1" , CCD = "C3" , ITYPE = "A"} , 

    new SampleItem(){ QCD = "Q1" , CCD = "C1" , ITYPE = "B"} , 
    new SampleItem(){ QCD = "Q1" , CCD = "C2" , ITYPE = "B"} , 
}; 

一個我怎樣才能得到3組像

第1組:

new SampleItem(){ QCD = "Q1" , CCD = "C1" , ITYPE = "B"} , 
new SampleItem(){ QCD = "Q1" , CCD = "C2" , ITYPE = "B"} , 

組2:

new SampleItem(){ QCD = "Q1" , CCD = "C1" , ITYPE = "A"} , 
new SampleItem(){ QCD = "Q1" , CCD = "C2" , ITYPE = "A"} , 
new SampleItem(){ QCD = "Q1" , CCD = "C3" , ITYPE = "A"} , 

組3:

new SampleItem(){ QCD = "Q1" , CCD = "C1" , ITYPE = "B"} , 
new SampleItem(){ QCD = "Q1" , CCD = "C2" , ITYPE = "B"} , 

通過LINQ

非常感謝您的任何建議。

+2

什麼你想要的,然後,它分裂時,值*更改*,而不是一個完整的組 - 沒有內置的LINQ操作;你將不得不手動編寫它。我會在一瞬間刺傷... – 2012-01-05 12:56:09

+0

組1與組3相同? – V4Vendetta 2012-01-05 12:58:43

+0

謝謝你的評論,是的,我已經通過循環實現它。但是,實際上這只是我的一部分代碼。我想找一個更清楚的方法來解決這個問題。 :) – shenhengbin 2012-01-05 13:00:19

回答

5

使用GroupAdjacent運營商,如one listed on Eric White's blog,你可以這樣做:

var groupedItems = lstTest.GroupAdjacent(p => new { p.QCD, p.ITYPE }); 
+0

WOW !!太棒了!!這是!謝謝!!!!! – shenhengbin 2012-01-05 13:05:55

4

(現在我後,我看到了類似的GroupAdjacent已經發布,但在這裏我要離開這個作爲備選實現相同的主要的)

隨着自定義擴展方法,等瞧:

static void Main() { 
    var lstTest = new List<SampleItem>() { 
     new SampleItem(){ QCD = "Q1" , CCD = "C1" , ITYPE = "B"} , 
     new SampleItem(){ QCD = "Q1" , CCD = "C2" , ITYPE = "B"} , 

     new SampleItem(){ QCD = "Q1" , CCD = "C1" , ITYPE = "A"} , 
     new SampleItem(){ QCD = "Q1" , CCD = "C2" , ITYPE = "A"} , 
     new SampleItem(){ QCD = "Q1" , CCD = "C3" , ITYPE = "A"} , 

     new SampleItem(){ QCD = "Q1" , CCD = "C1" , ITYPE = "B"} , 
     new SampleItem(){ QCD = "Q1" , CCD = "C2" , ITYPE = "B"} , 
    }; 
    foreach(var group in lstTest.Split(x => new { x.QCD, x.ITYPE})) { 
     Console.WriteLine("{0}, {1}", group[0].QCD, group[0].ITYPE); 
     foreach(var item in group) { 
      Console.WriteLine("\t{0}", item.CCD); 
     } 
    } 
} 
public static IEnumerable<TSource[]> Split<TSource, TValue>(
    this IEnumerable<TSource> source, Func<TSource, TValue> selector) 
{ 
    var comparer = EqualityComparer<TValue>.Default; 
    using(var iter = source.GetEnumerator()) { 
     if(iter.MoveNext()) { 
      List<TSource> buffer = new List<TSource>(); 
      buffer.Add(iter.Current); 
      TValue groupValue = selector(iter.Current); 
      while(iter.MoveNext()) { 
       var currentItem = iter.Current; 
       var currentValue = selector(currentItem); 
       if(!comparer.Equals(groupValue, currentValue)) { 
        var arr = buffer.ToArray(); 
        buffer.Clear(); 
        yield return arr; 
        groupValue = currentValue; 
       } 
       buffer.Add(currentItem); 
      } 
      yield return buffer.ToArray(); 
     } 
    } 
} 
+0

謝謝你慨答案~~!我已經學會了更多~~! – shenhengbin 2012-01-05 13:08:08

0

另一個GroupAdjacent implementa和灰:

// name your utility class how you want 
public static class MyEnumerable 
{ 
    /// <summary> 
    /// Cuts a sequence into groups according to a specified key selector function. 
    /// Similar to GroupBy, but only groups adjacent items. 
    /// Reduces a collection a,a,B,B,B,a,p,p,p,p to (a,a),(B,B,B),(a),(p,p,p,p). 
    /// </summary> 
    /// <typeparam name="TSource">The type of the elements of source.</typeparam> 
    /// <typeparam name="TKey">The type of the key returned by keySelector.</typeparam> 
    /// <param name="source">An <see cref="System.Collections.Generic.IEnumerable"/> whose elements to group.</param> 
    /// <param name="keySelector"> A function to extract the key for each element.</param> 
    /// <returns> 
    /// An IEnumerable&lt;IGrouping&lt;TKey, TSource&gt;&gt; in C# or 
    /// IEnumerable(Of IGrouping(Of TKey, TSource)) in Visual Basic 
    /// where each <see cref="System.Linq.IGrouping"/> 2 object contains a sequence of objects and a key. 
    /// </returns> 
    public static IEnumerable<IGrouping<TKey, TSource>> GroupAdjacentBy<TKey, TSource>(this IEnumerable<TSource> source, Func<TSource, TKey> keySelector) 
    { 
     using (var en = source.GetEnumerator()) 
     { 
      if (!en.MoveNext()) yield break; 
      var key = keySelector(en.Current); 
      var elements = new List<TSource> { en.Current }; 
      while (en.MoveNext()) 
      { 
       var nextKey = keySelector(en.Current); 
       if (!Equals(nextKey, key)) 
       { 
        yield return new Grouping<TKey, TSource>(key, elements); 
        key = nextKey; 
        elements = new List<TSource>(); 
       } 
       elements.Add(en.Current); 
      } 
      yield return new Grouping<TKey, TSource>(key, elements); 
     } 
    } 

這也可用於像

new[]{"one","seven","force","wow","bye"}.GroupAdjecent(s=>s.Length) 

含返回IGroupings

  • 3:一個
  • 5:7,力
  • 3:哇,再見