C#对象排名,多个标准

我正在为我编写的局域网方网站构建一个允许使用Round Robin锦标赛的插件。

一切进展顺利,但我对排名超过两个标准的最有效方法有一些疑问。

基本上,我想要以下排名布局:

Rank Wins TotalScore PersonE 1 5 50 PersonD 2 3.5 37 PersonA 2 3.5 37 PersonC 4 2.5 26 PersonB 5 2.5 24 PersonF 6 0 12 

在SQL服务器中,我会使用:

 SELECT [Person], RANK() OVER (ORDER BY Wins DESC, TotalScore DESC) [Rank], [Wins], [TotalScore] 

现在,我只有List,Dictionary等可以使用

特别:

 Dictionary wins = new Dictionary(); Dictionary score = new Dictionary(); 

有没有办法用LINQ做这种风格的排名?

如果没有,是否有一种可扩展的方式可以让我以后考虑Win-Loss-Draw而不仅仅是胜利,如果我选择的话?

编辑:

我改编了TheSoftwareJedi的答案:

 private class RRWinRecord : IComparable { public int Wins { get; set; } public int Losses { get; set; } public int Draws { get; set; } public double OverallScore { get; set; } public double WinRecord { get { return this.Wins * 1.0 + this.Draws * 0.5 + this.Losses * 0.0; } } public int CompareTo(object obj) { ... } public override bool Equals(object obj) { ... } public override int GetHashCode() { ... } public static bool operator ==(RRWinRecord lhs, RRWinRecord rhs) { ... } public static bool operator !=(RRWinRecord lhs, RRWinRecord rhs) { ... } public static bool operator >(RRWinRecord lhs, RRWinRecord rhs) { ... } public static bool operator =(RRWinRecord lhs, RRWinRecord rhs) { ... } public static bool operator <=(RRWinRecord lhs, RRWinRecord rhs) { ... } } ... int r = 1, lastRank = 1; RRWinRecord lastRecord = null; var ranks = from team in records.Keys let teamRecord = records[team] orderby teamRecord descending select new RRRank() { Team = team, Rank = r++, Record = teamRecord }; foreach (var rank in ranks) { if (rank.Record != null && lastRecord == rank.Record) { rank.Rank = lastRank; } lastRecord = rank.Record; lastRank = rank.Rank; string scoreDescription = String.Format("{0}-{1}-{2}", rank.Record.Wins, rank.Record.Losses, rank.Record.Draws); yield return new TournamentRanking(rank.Team, rank.Rank, scoreDescription); } yield break; 

这适用于非密集级别:

 static class Program { static IEnumerable GetResults(Dictionary wins, Dictionary scores) { int r = 1; double lastWin = -1; double lastScore = -1; int lastRank = 1; foreach (var rank in from name in wins.Keys let score = scores[name] let win = wins[name] orderby win descending, score descending select new Result { Name = name, Rank = r++, Score = score, Win = win }) { if (lastWin == rank.Win && lastScore == rank.Score) { rank.Rank = lastRank; } lastWin = rank.Win; lastScore = rank.Score; lastRank = rank.Rank; yield return rank; } } } class Result { public TournamentTeam Name; public int Rank; public double Score; public double Win; } 

排名不是太难。 只需将OrderBy和Select实现模式混合在一起,您就可以拥有一个易于使用的排名扩展方法。 像这样:

  public static IEnumerable Rank ( this IEnumerable source, Func keySelector, Func selector ) { if (!source.Any()) { yield break; } int itemCount = 0; T[] ordered = source.OrderBy(keySelector).ToArray(); TKey previous = keySelector(ordered[0]); int rank = 1; foreach (T t in ordered) { itemCount += 1; TKey current = keySelector(t); if (!current.Equals(previous)) { rank = itemCount; } yield return selector(t, rank); previous = current; } } 

这是一些测试代码

 string[] myNames = new string[] { "Bob", "Mark", "John", "Jim", "Lisa", "Dave" }; // var query = myNames.Rank(s => s.Length, (s, r) => new { s, r }); // foreach (var x in query) { Console.WriteLine("{0} {1}", xr, xs); } 

产生这些结果:

 1 Bob 1 Jim 3 Mark 3 John 3 Lisa 3 Dave 

假设您有一个List结构,其中Result对象具有以下参数…

 Pesron - string Rank - int Wins - double TotalScore - int 

您可以编写自定义比较器,然后将其传递给List.Sort(Comparison comparison)

或者,您可以让您的Result对象实现IComparable并将其粘贴到您的类中。

  #region IComparable Members public int CompareTo(Result obj) { if (this.Rank.CompareTo(obj.Rank) != 0) return this.Rank.CompareTo(obj.Rank); if (this.Wins.CompareTo(obj.Wins) != 0) return (this.Wins.CompareTo(obj.Wins); return (this.TotalScore.CompareTo(obj.TotalScore) ; } #endregion 

然后你可以调用List.Sort() ;

这可能是一个开始:

 Dictionary wins = new Dictionary(); Dictionary score = new Dictionary(); Dictionary ranks = new Dictionary(); int r = 1; ranks = ( from name in wins.Keys orderby wins[name] descending, scores[name] descending select new { Name = name, Rank = r++ }) .ToDictionary(item => item.Name, item => item.Rank); 

我意识到我已经迟到了,但无论如何我想要开枪。

这是一个专门使用LINQ的版本:

 private IEnumerable GetRankings(Dictionary wins, Dictionary scores) { var overallRank = 1; return from team in wins.Keys group team by new { Wins = wins[team], TotalScore = scores[team] } into rankGroup orderby rankGroup.Key.Wins descending, rankGroup.Key.TotalScore descending let currentRank = overallRank++ from team in rankGroup select new TeamRank(team, currentRank, rankGroup.Key.Wins, rankGroup.Key.TotalScore); } 

返回类型:

 public class TeamRank { public TeamRank(TournamentTeam team, int rank, double wins, double totalScore) { this.Team = team; this.Rank = rank; this.Wins = wins; this.TotalScore = totalScore; } public TournamentTeam Team { get; private set; } public int Rank { get; private set; } public double Wins { get; private set; } public double TotalScore { get; private set; } }