سؤال

أنا أقوم ببناء مكون إضافي لموقع Lan Party الإلكتروني الذي كتبته من شأنه أن يسمح باستخدام بطولة Robin Round.

كل شيء يسير على ما يرام، لكن لدي بعض الأسئلة حول الطريقة الأكثر كفاءة لتحتل معيارين.

في الأساس، أود تخطيط الترتيب التالي:

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

هل هناك طريقة للقيام بهذا النمط من الترتيب مع لينك؟

إذا لم يكن كذلك، هل هناك توسع الطريقة التي من شأنها أن تسمح لي لاحقا أن تأخذ لحساب السحب الفوز بدلا من فوز فقط إذا اخترت ذلك؟

يحرر:

بلدي التكيف عن إجابة 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) { ... }
    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<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;
}

نصائح أخرى

الترتيب ليس صعبا جدا. مجرد mishmash orderby وحدد أنماط التنفيذ معا ويمكن أن يكون لديك طريقة ملزمة الترتيب سهلة الاستخدام. مثله:

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

إليك بعض رمز الاختبار

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

على افتراض أن لديك List<Result> هيكل حيث Result الكائن لديه المعلمات التالية ...

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

يمكنك كتابة مقارنة مخصصة، ثم تمر ذلك إلى List.Sort(Comparison<Result> comparison)

البديل، يمكنك فقط جعل الخاص بك Result كائن تنفيذ IComparable<Result>والعصا هذا في صفك.

        #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<Result>.Sort();

قد يكون هذا بداية:

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

أدرك أنني متأخرا للحفلة، لكنني أردت أن تأخذ طلقة على أي حال.

فيما يلي نسخة تستخدم 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);
}

نوع الإرجاع:

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; }
}
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top