在LinQ中将相同的排名分配给相同的分数

时间:2014-05-27 07:44:35

标签: c# linq asp.net-mvc-4 rank

我正在MVC中编写一个LinQ查询,根据他们的分数返回学生的等级

// Merge the LB lists to get aggregated List, allot dummy rank(0)
var a = leaderboard.ToDictionary((kvp => kvp.Key),
(kvp => kvp.Value.leaderboard)).Values.SelectMany(x => x).GroupBy(student => student.stId).Select(
g => new Leaderboard { 
stId = g.Key, 
stName = g.Select(x => x.stName).First(), 
rank = 0, 
score = g.Select(x => x.score).Sum(), 
cName = g.Select(x => x.cName).First() 
});

// Arrange the records in descending order of scores for rank
lbList = a.ToList().OrderByDescending(q => q.score).ToList();
int rank = 1;
lbList = lbList.Select(c => { c.rank = rank++; return c; }).ToList();

但是对于相同的分数,这会返回不同的等级。看作分数是唯一没有时间分量的参数,如何更改此分数以返回相同分数的相同排名?

2 个答案:

答案 0 :(得分:0)

按顺序创建一个独特的分数集合,然后使用该集合中当前学生分数的位置作为他的排名:

var UniqueScores = a.OrderByDescending(x=>x.score).Select(x=>x.score).Distinct().ToArray;
lbList = lbList.Select(c => { c.rank = (UniqueScores.IndexOf(c.score) + 1); return c; }).ToList();

答案 1 :(得分:0)

序言

这段代码看起来很可疑:

var a = leaderboard.ToDictionary((kvp => kvp.Key),
(kvp => kvp.Value.leaderboard)).Values.SelectMany(x => x).GroupBy(student => student.stId).Select(
g => new Leaderboard { 
stId = g.Key, 
stName = g.Select(x => x.stName).First(), 
rank = 0, 
score = g.Select(x => x.score).Sum(), 
cName = g.Select(x => x.cName).First() 
});
  1. SelectMany(x => x)。这有什么意义?它什么也没做。
  2. g.Select(x => x.cName).First()。它不是最优的,也不是可读的:g.First().cName
  3. ToDictionary ...再次,在您的案例中没有任何操作,因为您最终只使用Values
  4. 所以,我会像这样重写它:

    var a = leaderboard.
        Select(x => x.Value.leaderboard).
        GroupBy(student => student.stId).
        Select(
            g => new Leaderboard { 
                stId = g.Key, 
                stName = g.First().stName,
                rank = 0, 
                score = g.Sum(x => x.score),
                cName = g.First().cName});
    

    排序

    有一点需要考虑。您的代码以ToList()结尾。如果你想将List<>作为输出,那么简单的for循环是我认为最好的解决方案:

    var lbList = a.OrderByDescending(x => x.score);
    int rank = 1;
    for (int i = 0; i < lbList.Count; ++i)
    {
        if (i > 0 && lbList[i - 1].score != lbList[i].score)
            ++rank;
        lbList[i].rank = rank;
    }
    

    如果您需要lbList作为IEnumerable<>,那么:

    var lbList = a.
        GroupBy(q => q.score).
        OrderByDescending(g => g.Key).
        SelectMany(
            (group, index) => group.Select(s => {
                s.rank = index + 1;
                return s;
            });