C# C对象的排序,多个标准
我正在为我编写的一个局域网派对网站构建一个插件,它允许使用循环赛 一切进展顺利,但我有一些问题,关于在两个标准上排名最有效的方法 基本上,我想要以下排名布局:C# C对象的排序,多个标准,c#,linq,linq-to-objects,ranking,C#,Linq,Linq To Objects,Ranking,我正在为我编写的一个局域网派对网站构建一个插件,它允许使用循环赛 一切进展顺利,但我有一些问题,关于在两个标准上排名最有效的方法 基本上,我想要以下排名布局: 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
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 server中,我将使用:
SELECT
[Person],
RANK() OVER (ORDER BY Wins DESC, TotalScore DESC) [Rank],
[Wins],
[TotalScore]
现在,我只有列表、字典等可供使用
具体而言:
Dictionary<TournamentTeam, double> wins = new Dictionary<TournamentTeam, double>();
Dictionary<TournamentTeam, double> score = new Dictionary<TournamentTeam, double>();
有没有办法用LINQ进行这种风格的排名
如果没有,是否有一种可扩展的方式,允许我以后考虑赢-输-抽,而不是仅仅考虑赢-如果我选择的话
编辑:
我对SoftwareEdi答案的改编:
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) { ... }
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;
这可能是一个开始:
Dictionary<TournamentTeam, double> wins = new Dictionary<TournamentTeam, double>();
Dictionary<TournamentTeam, double> score = new Dictionary<TournamentTeam, double>();
Dictionary<TournamentTeam, int> ranks = new Dictionary<TournamentTeam, int>();
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);
假设您有一个列表结构,其中结果对象具有以下参数
Pesron - string
Rank - int
Wins - double
TotalScore - int
您可以编写一个自定义比较器,然后将其传递给List.SortComparison comparison comparison
或者,您可以使结果对象实现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
然后,您可以只调用列表 这适用于非密集等级:
static class Program
{
static IEnumerable<Result> GetResults(Dictionary<TournamentTeam, double> wins, Dictionary<TournamentTeam, double> 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;
}
我意识到我参加晚会迟到了,但我无论如何都想试一试 以下是专门使用LINQ的版本:
private IEnumerable<TeamRank> GetRankings(Dictionary<TournamentTeam, double> wins, Dictionary<TournamentTeam, double> 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);
}
排名并不难。只需将OrderBy和Select实现模式混合在一起,就可以有一个易于使用的排名扩展方法。像这样:
public static IEnumerable<U> Rank<T, TKey, U>
(
this IEnumerable<T> source,
Func<T, TKey> keySelector,
Func<T, int, U> 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;
}
}
这产生了以下结果:
1 Bob
1 Jim
3 Mark
3 John
3 Lisa
3 Dave
这是一个很好的开始。我看看能不能加上平局是的,很好的开始+1。然而,我需要非密集的排名。我正在构建一个NUnit测试,以实现所需的行为。很快会回来的。添加了下面的非稠密溶液。本打算编辑这篇文章,但我认为它太不一样了,需要一个新的答案。不明白为什么这篇文章被否决了。您可以简单地实现自己的比较器,使用自己的公式来确定两个对象的相等性。任何配方都可以!我没有投反对票,但我需要非密集排序,这在您的解决方案中是不可用的。+1:啊,现在我已经清理了,我添加了一个类似于您的类,现在我看到这在哪里是有用的。请看问题,了解我是如何使用所有建议的。+1几乎完美!我所希望的是,排序参数的逻辑在一个地方,而不是在ORDERBY子句中,并且在if语句中。可能的错误修复:将lastRank设置为1,以便在最佳分数为-1的情况下,排名仍将设置为1。排序逻辑在一个地方。比较的逻辑是另一种。您可以使用CompareTo和Equals@John吉森-荣誉。修好了,很好!我所要做的就是在我的类上实现适当的操作符,等等。我可以根据任何东西进行排名!求爱谢谢所有伟大的答案,伙计们!这里有一个简单的答案:
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}", x.r, x.s);
}
1 Bob
1 Jim
3 Mark
3 John
3 Lisa
3 Dave