我如何通过Linq实现它?

时间:2012-01-05 12:53:33

标签: c# 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});

但现在,如果My List的订单与下面的订单相同

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

谢谢你的任何建议。

3 个答案:

答案 0 :(得分:5)

使用GroupAdjacent运算符,例如one listed on Eric White's blog,您可以执行以下操作:

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

答案 1 :(得分:4)

(现在我发帖了,我发现有一个类似的GroupAdjacent已发布,但我会把它留在这里作为同一主体的替代实现)

使用自定义扩展方法,et voila:

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();
        }
    }
}

答案 2 :(得分:0)

另一个GroupAdjacent实现:

// 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:七,强迫
  • 3:哇,再见