【问题标题】:Linq List Ranking in C#C#中的Linq列表排名
【发布时间】:2020-06-19 02:17:06
【问题描述】:

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

  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 中包含正确的排名。

【问题讨论】:

    标签: c# linq observablecollection


    【解决方案1】:

    您必须OrderByDescendinggroupedData(有总分)而不是包含非总分的原始数据。

    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));
    

    【讨论】:

    • 您好,感谢您的回复。我尝试了您提出的解决方案,但我仍然没有得到正确的排名:S
    • 排名在列表位置编码,我将更新答案以在Person.Rank中提供它
    • 完美!现在我需要弄清楚如何确定得分相同的人的排名。非常感谢:)
    • 我会按分数分组,按分数排序,然后通过按每组中的元素数聚合来创建排名
    【解决方案2】:

    不久前我问了一个类似的问题。我的问题是,如果人们的分数相同,它会给这个人分配错误的排名。使用您当前的代码,如果 John 的得分也为 7,他将排名第 2,因为您按得分排序,并且当他真正并列第 1 时,仅使用其在列表中的位置。

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

    【讨论】:

    • 感谢您的回复。您能否解释一下解决方案,因为我不明白它的实现是如何解决问题的:)
    【解决方案3】:

    扩展方法做排名怎么样:

    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);
                }
            }
    

    使用profiles.SelectRank(x =&gt; x.Score, (x, r) =&gt; new { x.Name, Rank = r })。此方法仅对源进行 1 次迭代。我建议使用已排序的source 参数。

    【讨论】:

      【解决方案4】:

      在此处添加完成代码以作为锦标赛示例:

      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
              });
      

      结果:

      【讨论】:

        猜你喜欢
        • 2020-06-10
        • 1970-01-01
        • 1970-01-01
        • 2020-04-01
        • 2021-10-23
        • 1970-01-01
        • 1970-01-01
        • 2013-09-16
        • 2018-11-21
        相关资源
        最近更新 更多