考虑以下记录:
_______________________
Id S1 S2 | S3 S4 S5 |
--------------------|----------------------|
1 5 7 | 8 2 5 |
2 22 24 | 7 9 10 |
3 19 17 | 8 2 3 |
4 7 8 | 9 1 0 |
5 15 1 | 7 9 10 |
________________________
我想根据S3,S4,S5列中的降序从每条记录中获得前2个属性名称 - 类似于这些记录:
Id 1st Top 2nd Top
---------------------------
1 S3 (8) S5 (5)
2 S5 (10) S4 (9)
3 S3 (8) S5 (3)
4 S3 (9) S4 (1)
5 S5 (10) S4 (9)
我如何使用linq做到这一点?
注意:S3 / S4 / S5是整数类型。
我想要字符串值中的前2个属性名称。
答案 0 :(得分:1)
首先,您需要像这样修复数据:
var data = records.Select(r=>new {Id=r.Id,Field="S1",Value=r.S1})
.Concat(records.Select(r=>new {Id=r.Id,Field="S2",Value=r.S2}))
.Concat(records.Select(r=>new {Id=r.Id,Field="S3",Value=r.S3}))
.Concat(records.Select(r=>new {Id=r.Id,Field="S4",Value=r.S4}))
.Concat(records.Select(r=>new {Id=r.Id,Field="S5",Value=r.S5}));
然后你可以操纵它(虽然一个简单的组可能只是更好):
var results = data
.Where(d=>d.Field == "S3" || d.Field == "S4" || d.Field == "S5")
.GroupBy(d=>d.Id)
.Select(grp=>new {
Id,
First = d.OrderByDescending(f=>f.Value).First(),
Second = d.OrderByDescending(f=>f.Value).Skip(1).First()
});
这是做到这一点的漫长道路,但它是最通用的。你根本不需要连接s1 / s2,但我把它们留在那里只是因为你可能想要对这些数据做出的其他查询可能需要它们。
打印出来:
foreach(var rec in data.OrderBy(r=>r.Id))
{
Console.WriteLine("{0} {1} ({2}) {3} ({4}),
rec.Id, rec.First.Field, rec.First.Value, rec.Second.Field, rec.Second.Value);
}
或者你可以这样做:
var data = records.Select(r=>new {Id=r.Id,Field="S3",Value=r.S3})
.Concat(records.Select(r=>new {Id=r.Id,Field="S4",Value=r.S4}))
.Concat(records.Select(r=>new {Id=r.Id,Field="S5",Value=r.S5}));
foreach(var rec in data
.GroupBy(z=>z.Id)
.OrderBy(z=>z.Id))
{
Console.WriteLine("{0} {1} ({2}) {3} ({4}),
rec.Key,
rec.OrderByDescending(f=>f.Value).First().Field,
rec.OrderByDescending(f=>f.Value).First().Value,
rec.OrderByDescending(f=>f.Value).Skip(1).First().Field,
rec.OrderByDescending(f=>f.Value).Skip(1).First().Value);
}
或者你可以生成这样的规范化数据,如果它对你更有意义:
var data = records.Select(r=> new {
Id=r.Id,
Values=new[]{
new {Field="S3",Value=r.S3},
new {Field="S4",Value=r.S4},
new {Field="S5",Value=r.S5}}});