title: C# Ranking of objects, multiple criteria
body: <p>I am building a plugin for a LAN party website that I wrote that would allow the use of a Round Robin tournament.</p>
  
  <p>All is going well, but I have some questions about the most efficient way to rank over two criteria.</p>
  
  <p>Basically, I would like the following ranking layout:</p>
  
  <pre><code>         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
  </code></pre>
  
  <p>In SQL server, I would use:</p>
  
  <pre><code>SELECT
      [Person],
      RANK() OVER (ORDER BY Wins DESC, TotalScore DESC) [Rank],
      [Wins],
      [TotalScore]
  </code></pre>
  
  <p>Now, I only have List, Dictionary, and etc. to work with</p>
  
  <p>Specifically:</p>
  
  <pre><code>Dictionary&lt;TournamentTeam, double&gt; wins = new Dictionary&lt;TournamentTeam, double&gt;();
  Dictionary&lt;TournamentTeam, double&gt; score = new Dictionary&lt;TournamentTeam, double&gt;();
  </code></pre>
  
  <p><strong>Is there a way to do this style of ranking with LINQ?</strong></p>
  
  <p>If not, is there an <em>extensible</em> way that would allow me later to take in to account Win-Loss-Draw instead of just wins if I choose to?</p>
  
  <p><strong>Edit:</strong></p>
  
  <p>My adaptation of TheSoftwareJedi's answer:</p>
  
  <pre><code>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 &gt;(RRWinRecord lhs, RRWinRecord rhs) { ... }
      public static bool operator &lt;(RRWinRecord lhs, RRWinRecord rhs) { ... }
      public static bool operator &gt;=(RRWinRecord lhs, RRWinRecord rhs) { ... }
      public static bool operator &lt;=(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 &amp;&amp; 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;
  </code></pre>