Linq列表中的C#排名

时间:2017-08-23 11:43:54

标签: c# linq observablecollection

我有以下列表,其中包含名单和分数列表。我使用linq获得的分数得到了peope列表的总和:

  Name  Score
   Ed    5
   John  6
   Sara  7
   Dean  3
   Nora  4

所以我能够对列表进行分组并进行总结,但现在我正在尝试根据分数对这些进行排名。所以我想获得以下列表:

Rank Name Score
 1   Sara  7
 2   John  6
 3   Ed    5
 4   Nora  4
 5   Dean  3

但我使用的linq代码似乎并没有为我找到合适的排名。

这是我制作列表并进行总结和排名的代码:

    public class Person
    {

        public int Rank { get; set; }
        public string Name { get; private set; }
        public int Score { get; set; }

        public Person(int rank, string name, int score)
        {
            Rank = rank;
            Name = name;
            Score = score;

        }
    }

    public ObservableCollection<Person> Persons { get; set; }
    public MainWindow()
    {            
 Persons = new ObservableCollection<Person>();
        var data = lines.Select(line => {
        var column = line.Split(',');
        var name = column[0];
        int score = int.Parse(column[1]);
        int rank =0; 
        return new { name, score, rank };
    });

        var groupedData = data.OrderByDescending(x => x.score).GroupBy(p => p.name).Select((g, i) => new { name = g.Key, rank=i+1, score = g.Sum(p => p.score)});

    var persons = groupedData.Select(p => new Person(p.rank, p.name, p.score));

    foreach (var person in persons) {
        Persons.Add(person);
    }
    datagrid.ItemsSource = Persons;
}

我只想知道如何在linq中包含正确的排名。

4 个答案:

答案 0 :(得分:5)

您必须OrderByDescending groupedData(总得分),而不是包含未加总的个人得分的原始数据。

var persons = groupedData.Select(p => new Person(p.rank, p.name, p.score)).OrderByDescending(x => x.Score);

编辑 :(将正确的排名放入Person.Rank

var groupedData = data.GroupBy(p => p.name).Select(g => new { name = g.Key, score = g.Sum(p => p.score)}).OrderByDescending(x => x.score);
var persons = groupedData.Select((p,i) => new Person(i+1, p.name, p.score));

答案 1 :(得分:0)

前一阵子我问了一个类似的问题。我的问题是,如果人们有相同的分数,它将为该人分配错误的等级。根据你当前的代码,如果John的得分为7,他将排名第2,因为你按照得分排序,只是在他真正并列#1时使用它在列表中的位置。

以下是我的问题和解决方案:Get the index of item in list based on value

答案 2 :(得分:0)

扩展方法如何进行排名:

In keyword: 3
In test: 3
In keyword: 5

用法public static IEnumerable<TResult> SelectRank<TSource, TValue, TResult>(this IEnumerable<TSource> source, Func<TSource, TValue> valueSelector, Func<TSource, int, TResult> selector) where TValue : struct { TValue? previousValue = default(TValue?); var count = 0; var rank = 0; foreach (var item in source) { count++; var value = valueSelector(item); if (!value.Equals(previousValue)) { rank = count; previousValue = value; } yield return selector(item, rank); } } 。此方法仅对源执行1次迭代。我确实建议使用排序后的profiles.SelectRank(x => x.Score, (x, r) => new { x.Name, Rank = r })参数。

答案 3 :(得分:0)

在此处添加代码以完成比赛示例:

var entriesByPoints = tournament.Entries.GroupBy(g=>g.Picks.Sum(s=>s.TournamentContestant.TotalScoreTargetAllocatedPoints)).Select((group)=> new { 
            Points = group.Key,
            Entries = group.ToList()
            });

var entriesByRankWithPoints = entriesByPoints.OrderByDescending(ob=>ob.Points).Select((p,i) => new {
            Rank = 1 + (entriesByPoints.Where(w=>w.Points > p.Points).Sum(s=>s.Entries.Count())), 
            Points = p.Points, 
            Entries = p.Entries
        });

结果:

{{3}}