2011-11-10 41 views
4

考慮下面的代碼:在我的LIST中排名位置的解決方案?

class Results 
{ 
    public int playerId; 
    public int score; 
    public int section; 
    public int position; 
    public Results(int _playerId, int _score, int _section) 
    { 
     playerId = _playerId; 
     score = _score; 
     section = _section; 
    } 
} 

public void RankMyResults() 
{ 
    List<Results> myResultList = new List<Results>(); 

    myResultList.Add(new Results(1,232, 1)); 
    myResultList.Add(new Results(2,213, 1)); 
    // Add a lot of more results 

    // Iteriate over the items to set the position 
} 

我想設置位置1爲在每個部分中的最高得分,位置2爲第二高等等。

此外,如果兩個人有相同的得分的位置應該是這樣的

Position Score PlayerId Section 
1   135  23  1 
1   135  43  1 
3   131  45  1 

如本例將跳過位置2

是否有使用LINQ來做到這一點的好方法或者例如使用列表對象中的某些選擇,排序功能?

我自己的解決方案遍歷列表並不好!

+1

爲什麼你的解決方案不好? LINQ可以簡化一些查詢,但有時使用循環的正常命令代碼更好。 LINQ沒有使循環過時。 – svick

+0

您可以發佈您的解決方案,我們可以嘗試使用LINQ簡化(?!)它,但這並不總是有意義 – sll

+3

請參見[C#排名對象,多個條件](http://stackoverflow.com/questions/932300/ c-sharp-ranking-of-objects-multiple-criteria)有幾個很好的解決方案 – sll

回答

8

我只是前幾天寫這些擴展方法:

#region RankBy 

    public static IEnumerable<TResult> RankBy<TSource, TKey, TResult>(
     this IEnumerable<TSource> source, 
     Func<TSource, TKey> keySelector, 
     Func<TSource, int, TResult> resultSelector) 
    { 
     return source.RankBy(keySelector, null, false, resultSelector); 
    } 

    public static IEnumerable<TResult> RankBy<TSource, TKey, TResult>(
     this IEnumerable<TSource> source, 
     Func<TSource, TKey> keySelector, 
     IComparer<TKey> comparer, 
     Func<TSource, int, TResult> resultSelector) 
    { 
     return source.RankBy(keySelector, comparer, false, resultSelector); 
    } 

    public static IEnumerable<TResult> RankByDescending<TSource, TKey, TResult>(
     this IEnumerable<TSource> source, 
     Func<TSource, TKey> keySelector, 
     IComparer<TKey> comparer, 
     Func<TSource, int, TResult> resultSelector) 
    { 
     return source.RankBy(keySelector, comparer, true, resultSelector); 
    } 

    public static IEnumerable<TResult> RankByDescending<TSource, TKey, TResult>(
     this IEnumerable<TSource> source, 
     Func<TSource, TKey> keySelector, 
     Func<TSource, int, TResult> resultSelector) 
    { 
     return source.RankBy(keySelector, null, true, resultSelector); 
    } 

    private static IEnumerable<TResult> RankBy<TSource, TKey, TResult>(
     this IEnumerable<TSource> source, 
     Func<TSource, TKey> keySelector, 
     IComparer<TKey> comparer, 
     bool descending, 
     Func<TSource, int, TResult> resultSelector) 
    { 
     comparer = comparer ?? Comparer<TKey>.Default; 

     var grouped = source.GroupBy(keySelector); 
     var ordered = 
      descending 
       ? grouped.OrderByDescending(g => g.Key, comparer) 
       : grouped.OrderBy(g => g.Key, comparer); 

     int totalRank = 1; 
     foreach (var group in ordered) 
     { 
      int rank = totalRank; 
      foreach (var item in group) 
      { 
       yield return resultSelector(item, rank); 
       totalRank++; 
      } 
     } 
    } 

    #endregion 

    #region DenseRankBy 

    public static IEnumerable<TResult> DenseRankBy<TSource, TKey, TResult>(
     this IEnumerable<TSource> source, 
     Func<TSource, TKey> keySelector, 
     Func<TSource, int, TResult> resultSelector) 
    { 
     return source.DenseRankBy(keySelector, null, false, resultSelector); 
    } 

    public static IEnumerable<TResult> DenseRankBy<TSource, TKey, TResult>(
     this IEnumerable<TSource> source, 
     Func<TSource, TKey> keySelector, 
     IComparer<TKey> comparer, 
     Func<TSource, int, TResult> resultSelector) 
    { 
     return source.DenseRankBy(keySelector, comparer, false, resultSelector); 
    } 

    public static IEnumerable<TResult> DenseRankByDescending<TSource, TKey, TResult>(
     this IEnumerable<TSource> source, 
     Func<TSource, TKey> keySelector, 
     IComparer<TKey> comparer, 
     Func<TSource, int, TResult> resultSelector) 
    { 
     return source.DenseRankBy(keySelector, comparer, true, resultSelector); 
    } 

    public static IEnumerable<TResult> DenseRankByDescending<TSource, TKey, TResult>(
     this IEnumerable<TSource> source, 
     Func<TSource, TKey> keySelector, 
     Func<TSource, int, TResult> resultSelector) 
    { 
     return source.DenseRankBy(keySelector, null, true, resultSelector); 
    } 

    private static IEnumerable<TResult> DenseRankBy<TSource, TKey, TResult>(
     this IEnumerable<TSource> source, 
     Func<TSource, TKey> keySelector, 
     IComparer<TKey> comparer, 
     bool descending, 
     Func<TSource, int, TResult> resultSelector) 
    { 
     comparer = comparer ?? Comparer<TKey>.Default; 

     var grouped = source.GroupBy(keySelector); 
     var ordered = 
      descending 
       ? grouped.OrderByDescending(g => g.Key, comparer) 
       : grouped.OrderBy(g => g.Key, comparer); 

     int rank = 1; 
     foreach (var group in ordered) 
     { 
      foreach (var item in group) 
      { 
       yield return resultSelector(item, rank); 
      } 
      rank++; 
     } 
    } 

    #endregion 

可以按如下方式使用它們:

var rankedPlayers = players.RankByDescending(
           p => p.Score, 
           (p, r) => new { Rank = r, Player = p }); 

RankByDenseRankBy之間的區別是,RankBy創建「間隙」(例如1,1,3,3,3,6 ...)而DenseRankBy不(1,1,2,2,2,3 ...)

0

我修改了那些grea t方法,以保持原始順序。排序方法不應改變元素的順序,它們應該對它們進行排序並以輸入收集的原始順序返回元素。

private static IEnumerable<TResult> RankBy<TSource, TKey, TResult>(
    this IEnumerable<TSource> source, 
    Func<TSource, TKey> keySelector, 
    IComparer<TKey> comparer, 
    bool descending, 
    Func<TSource, int, TResult> resultSelector) 
{ 
    var comp0 = comparer ?? Comparer<TKey>.Default; 
    var comp = descending ? Comparer<TKey>.Create((x, y) => -comp0.Compare(x, y)) : comp0; 

    var keys = source.Select(x => keySelector(x)).ToArray(); 
    var indexes = Enumerable.Range(0, keys.Length).ToArray(); 
    Array.Sort<TKey, int>(keys, indexes, comp); 

    var groups = new int[keys.Length]; 
    int group = 0; 
    int index = 0; 
    for (int j = 1; j < keys.Length; ++j) 
    { 
     ++index; 
     if (comp.Compare(keys[j], keys[j - 1]) != 0) 
     { 
      group += index; 
      index = 0; 
     } 
     groups[indexes[j]] = group; 
    } 

    index = 0; 
    foreach (var item in source) 
    { 
     yield return resultSelector(item, groups[index++] + 1); 
    } 
} 


private static IEnumerable<TResult> DenseRankBy<TSource, TKey, TResult>(
    this IEnumerable<TSource> source, 
    Func<TSource, TKey> keySelector, 
    IComparer<TKey> comparer, 
    bool descending, 
    Func<TSource, int, TResult> resultSelector) 
{ 
    var comp0 = comparer ?? Comparer<TKey>.Default; 
    var comp = descending ? Comparer<TKey>.Create((x, y) => -comp0.Compare(x, y)) : comp0; 

    var keys = source.Select(x => keySelector(x)).ToArray(); 
    var indexes = Enumerable.Range(0, keys.Length).ToArray(); 
    Array.Sort<TKey, int>(keys, indexes, comp); 

    var groups = new int[keys.Length]; 
    int group = 0; 
    for (int j = 1; j < keys.Length; ++j) 
    { 
     if (comp.Compare(keys[j], keys[j - 1]) != 0) 
      ++group; 
     groups[indexes[j]] = group; 
    } 

    int index = 0; 
    foreach (var item in source) 
    { 
     yield return resultSelector(item, groups[index++] + 1); 
    } 
} 
相關問題