我有以下列表,其中包含名单和分数列表。我使用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中包含正确的排名。
答案 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}}