Linq选择集合中的第一个活动记录

时间:2019-05-20 21:54:33

标签: c# linq

我正在尝试返回未取消状态的文档的最新修订。但是,如果文档的所有修订都被取消,则它仍应以已取消状态返回最多的修订。

数据看起来像: ID | Name | Rev | Status 00 | Manual | 000 | Active 00 | Manual | 001 | Active 00 | Manual | 002 | Active 00 | Manual | 003 | Active 00 | Manual | 004 | Active //return this one

ID | Name | Rev | Status 01 | Manual2 | 000 | Active 01 | Manual2 | 001 | Active 01 | Manual2 | 002 | Active 01 | Manual2 | 003 | Active //return this one 01 | Manual2 | 004 | Cancel

ID | Name | Rev | Status 02 | Manual3 | 000 | Cancel 02 | Manual3 | 001 | Cancel 02 | Manual3 | 002 | Cancel 02 | Manual3 | 003 | Cancel 02 | Manual3 | 004 | Cancel //return this one

我可以轻松地对记录进行分组和排序。我还可以过滤已取消状态的记录,但是对于第3个数据集,所有文档都处于已取消状态,并且出现异常。

List<Records> r = records
    .GroupBy(a => a.ID)
    .Select(b => new Record
            {
                ID = b.Key,
                Name = b.First().Name,
                Rev = b.OrderByDescending(o => o.Rev)
                       .First(x=> x.status != "Cancel").Rev
        }).ToList();

6 个答案:

答案 0 :(得分:2)

您所拥有的将近可用,可以在ThenBy之后使用OrderBy添加后续顺序:

List<Records> r = records
    .GroupBy(a => a.ID)
    .Select(b => new Record
            {
                ID = b.Key,
                Name = b.First().Name,
                Rev = b.OrderBy(o => o.status == "Cancel")
                       .ThenByDescending(o => o.Rev)
                       .First().Rev
        }).ToList();

注意:在本示例中,我在status == "Cancel"上以false < true的价格订购。


编辑

根据注释部分对其他状态的要求:您可以创建一个函数,将状态转换为数字等级:

public int GetStatusRank(string status)
{
    switch (status)
    {
        case "active":
            return 0;
        case "endorsed"
            return 1;
        case "cancelled":
            return 2;
        //etc...
        default:
            return int.MaxValue;
    }
}

然后您可以在OrderBy中使用它:

...b.OrderBy(o => GetStatusRank(o.status))

答案 1 :(得分:1)

以下查询首先按StatusRev对项进行排序。然后group by每个ID都选择一次。 distinctRecord.First()返回该组的最高项目,因此返回顺序。

var query =
    from record in records
    orderby record.Status ascending, // Active before Cancel ('A' is alphabetically before 'C')
        record.Rev descending // highest revision first
    group record by record.ID
    into distinctRecord
    select distinctRecord.First();
var r = query.ToList();

这很酷的事情是,您无需创建Record的新实例。而是从集合中带回实际的对象。


因为您需要创建Record的新实例,并且不使用对集合中实例的引用。您可以做到,就像我在评论中也已经解释过一样:

var query =
    from record in records
    orderby record.Status ascending, // Active before Cancel ('A' is alphabetically before 'C')
        record.Rev descending // highest revision first
    group record by record.ID
    into distinctRecord
    select new Record { 
        ID = distinctRecord.Key,
        Name = distinctRecord.First().Name,
        Rev = distinctRecord.First().Rev,
        Status = distinctRecord.First().Status
    };
var r = query.ToList();

答案 2 :(得分:0)

尝试一下:

.First(x=> x.status != "Cancel" || x.status == "Cancel")

答案 3 :(得分:0)

List<Records> r = records
                .OrderByDescending(x => x.Status != "Cancel")
                .ThenBy(r => r.Rev).ToList();

在(r => r.Rev)之后,您可以根据需要进行其他排序。只需使用.ThenBy(...)

答案 4 :(得分:0)

您可以尝试以下方法:

  • 使用Revision对象(活动或取消)创建匿名对象
  • 使用Rev属性创建记录的集合。

    var r = records.GroupBy(x => new {x.Id, x.Name})
                   .Select(x => new {
                       ID = x.Key.ID,
                       Name = x.Key.Name,
                       RevObj = x.OrderBy(y => y.Rev).LastOrDefault(y => y.Status != "Cancel") ??
                                x.OrderBy(y => y.Rev).Last(y => y.Status == "Cancel")
                   })
                   .ToArray()
                   .Select(x => new Record() {
                       ID = x.ID,
                       Name = x.Name,
                       Rev = x.RevObj.Rev
                   })
                   .ToList();
    

答案 5 :(得分:0)

我将基于 Aggregate -method的方法使用减少量:

    var resul = list
        .GroupBy(
            k => k.ID,
            (key, groups) =>
                groups.Aggregate((accumulatedItem, item) =>
                {
                    if (accumulatedItem.Status == item.Status)
                    {
                        return string.Compare(accumulatedItem.Rev, item.Rev) >= 0
                            ? accumulatedItem
                            : item;
                    }

                    return accumulatedItem.Status == "Active"
                        ? accumulatedItem
                        : item;
                })
            )
        .ToArray();

    var list = new[] {
        new Record("00", "Manual", "000","Active"),
        new Record("00", "Manual", "001","Active"),
        new Record("00", "Manual", "002","Active"),
        new Record("00", "Manual", "003","Active"),
        new Record("00", "Manual", "004","Active"),
        new Record("01", "Manual2", "000", "Active"),
        new Record("01", "Manual2", "001", "Active"),
        new Record("01", "Manual2", "002", "Active"),
        new Record("01", "Manual2", "003", "Active"),
        new Record("01", "Manual2", "004", "Cancel"),
        new Record("02", "Manual3", "000", "Cancel"),
        new Record("02", "Manual3", "001", "Cancel"),
        new Record("02", "Manual3", "002", "Cancel"),
        new Record("02", "Manual3", "003", "Cancel"),
        new Record("02", "Manual3", "004", "Cancel")
        };

public class Record
{
    public Record(string id, string name, string rev, string status)
    {
        ID = id;
        Name = name;
        Rev = rev;
        Status = status;
    }
    public string ID { get; set; }
    public string Name { get; set; }
    public string Rev { get; set; }
    public string Status { get; set; }
}
相关问题