我正在尝试返回未取消状态的文档的最新修订。但是,如果文档的所有修订都被取消,则它仍应以已取消状态返回最多的修订。
数据看起来像:
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();
答案 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)
以下查询首先按Status
和Rev
对项进行排序。然后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)
您可以尝试以下方法:
使用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; }
}