LINQ query — Data aggregation (Group Adjacent)

前端 未结 7 2000
失恋的感觉
失恋的感觉 2020-12-03 03:09

Let\'s take a class called Cls:

public class Cls
{
    public int SequenceNumber { get; set; }
    public int Value { get; set; }
}
7条回答
  •  温柔的废话
    2020-12-03 04:00

    You can use Linq's GroupBy in a modified version which groups only if the two items are adjacent, then it's easy as:

    var result = classes
        .GroupAdjacent(c => c.Value)
        .Select(g => new { 
            SequenceNumFrom = g.Min(c => c.SequenceNumber),
            SequenceNumTo = g.Max(c => c.SequenceNumber),  
            Value = g.Key
        });
    
    foreach (var x in result)
        Console.WriteLine("SequenceNumFrom:{0} SequenceNumTo:{1} Value:{2}", x.SequenceNumFrom, x.SequenceNumTo, x.Value);
    

    DEMO

    Result:

    SequenceNumFrom:1  SequenceNumTo:2  Value:9
    SequenceNumFrom:3  SequenceNumTo:5  Value:15
    SequenceNumFrom:6  SequenceNumTo:6  Value:30
    SequenceNumFrom:7  SequenceNumTo:7  Value:9
    

    This is the extension method to to group adjacent items:

    public static IEnumerable> GroupAdjacent(
            this IEnumerable source,
            Func keySelector)
        {
            TKey last = default(TKey);
            bool haveLast = false;
            List list = new List();
            foreach (TSource s in source)
            {
                TKey k = keySelector(s);
                if (haveLast)
                {
                    if (!k.Equals(last))
                    {
                        yield return new GroupOfAdjacent(list, last);
                        list = new List();
                        list.Add(s);
                        last = k;
                    }
                    else
                    {
                        list.Add(s);
                        last = k;
                    }
                }
                else
                {
                    list.Add(s);
                    last = k;
                    haveLast = true;
                }
            }
            if (haveLast)
                yield return new GroupOfAdjacent(list, last);
        }
    }
    

    and the class used:

    public class GroupOfAdjacent : IEnumerable, IGrouping
    {
        public TKey Key { get; set; }
        private List GroupList { get; set; }
        System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
        {
            return ((System.Collections.Generic.IEnumerable)this).GetEnumerator();
        }
        System.Collections.Generic.IEnumerator System.Collections.Generic.IEnumerable.GetEnumerator()
        {
            foreach (var s in GroupList)
                yield return s;
        }
        public GroupOfAdjacent(List source, TKey key)
        {
            GroupList = source;
            Key = key;
        }
    }
    

提交回复
热议问题