Linq查询对每个组中的项目和查询进行分组

时间:2013-05-29 14:03:18

标签: c# linq lambda

所以,我有一个看起来像这样的列表。它基本上是一堆项目的状态历史,最近的状态代表当前状态。

Record   Id      State       Date
=====    ===     =========  =======
1        A       Waiting     Jan 01
2        A       InProgress  Jan 02
3        A       Finished    Jan 03
4        B       Waiting     Jan 02
5        C       Waiting     Jan 01
6        C       InProgress  Jan 02
7        D       Waiting     Jan 01
8        D       InProgress  Jan 02

我正在寻找的是能够查询每个项目的“当前”状态。 例如,我想说:“给我所有的ID都是'InProgress'”并得到Id D和Id C,但不是Id A(因为它的最新状态是'完成')。

我知道我必须做一些分组和一些订购或Maxing,但我不能完全把它们放在一起。

3 个答案:

答案 0 :(得分:9)

myList.GroupBy(m => m.Id)
.Select(g => g.OrderByDescending(x => x.Date).First())
.Where(<your filter>);

答案 1 :(得分:2)

这里有一些代码可以做你想要的。它获取每个id的最新状态并忽略已完成的记录。我已经提供了一个完整的工作示例,您可以运行(并希望适应您的实际数据)。

//the example data provided by the OP
var data = new []
{
    new { Record = 1, Id = "A", State = "Waiting", Date = new DateTime(2013, 1, 1) },
    new { Record = 2, Id = "A", State = "InProgress", Date = new DateTime(2013, 1, 2) },
    new { Record = 3, Id = "A", State = "Finished", Date = new DateTime(2013, 1, 3) },        
    new { Record = 4, Id = "B", State = "Waiting", Date = new DateTime(2013, 1, 1) },        
    new { Record = 5, Id = "C", State = "Waiting", Date = new DateTime(2013, 1, 1) },
    new { Record = 6, Id = "C", State = "InProgress", Date = new DateTime(2013, 1, 2) },        
    new { Record = 7, Id = "D", State = "Waiting", Date = new DateTime(2013, 1, 1) },
    new { Record = 8, Id = "D", State = "InProgress", Date = new DateTime(2013, 1, 2) },
};

var query = from d in data
            //put the newest record first
            orderby d.Date descending
            //group by the id
            group d by d.Id into groupedById
            //get the latest record for each id
            let latest = groupedById.First()
            //filter out finished records
            where latest.State != "Finished"
            select latest;

这是LinqPad的输出。

enter image description here

你会注意到我们拥有每个项目的最新状态,除了因为它已经完成而被忽略的“A”。

答案 2 :(得分:1)

如果这是LINQ to Objects(假设记录按正确的顺序排列),你可以这样做:

var latestById = records.GroupBy(record => record.Id)
                        .ToDictionary(group => group.Key, group => group.Last());

这是因为GroupBy guarantees that“分组中的元素按它们在源中出现的顺序产生。”

如果您无法保证记录顺序,我会这样做:

var latestById = records.GroupBy(record => record.Id)
                        .Select(group => group.MaxBy(r => r.Date))
                        .ToDictionary(record => record.Id);

其中MaxBy来自moreLinq

顺便说一句,如果这是LINQ to SQL,我会这样做:

var latestById = records.GroupBy(record => record.Id)
                        .Select(group => group.OrderByDescending(r => r.Date).First())
                        .AsEnumerable()
                        .ToDictionary(record => record.Id);