简体   繁体   中英

Linq for calculating rank with group and orderby

I am trying to calculate the rank of objects. Since multiple objects can have the same score I would need to group them so they get the same rank.

public class RankedItem {

  public string Name {get; set;}
  public int Score {get; set; }
  public int Rank {get; set; }

  public RankedItem(string name, int score) {
     Name = name;
     Score = score;
  }

}

public void CalculateRanks() {

  List<RankedItem> items = new List<RankedItems> {
    new RankedItem("A", 3),
    new RankedItem("B", 2),
    new RankedItem("C", 3),
    new RankedItem("D", 1),
    new RankedItem("E", 2)
  };
 
  IOrderedEnumerable<IGrouping<int, RankedItems>> rankedItems = items.GroupBy(i => b.Score).OrderBy(g => g.Key);

  
}

How can I set the rank now, so that rank 1 will be assigned to the highest score?

You have basically 2 options here. Linq or Loop. For both options you should use OrderByDescending since your score rank relationship is inverse. Then you can use the index + 1 to assign the ranks.

  1. Loop.

for this option you need a collection to hold your groupings which can be iterated using the index [ ] operator. This is not possible in IOrderedEnumerable . So I suggest to use a List :

List<IGrouping<int, RankedItem>> rankedItems = items.GroupBy(b => b.Score)
                                                    .OrderByDescending(g => g.Key)
                                                    .ToList();

Now you can simply loop through the list having the index and loop again through all elements of each group to use the index to assign the rank:

for (int i = 0; i < rankedItems.Count(); i++)
{
    IGrouping<int, RankedItem> grouping = rankedItems[i];
    foreach (var element in grouping)
    {
        element.Rank = i + 1;
    }
}
  1. LINQ:

Use the index in this Select overload statement and create new objects using your constructor:

List<RankedItem> rankedItems = items.GroupBy(b => b.Score)
                                    .OrderByDescending(g => g.Key)
                                    .SelectMany((item, index) => item.Select(inner => 
                                            new RankedItem(inner.Name, item.Key) {Rank = index + 1})
                                    ).ToList();

Outcome:

在此处输入图像描述

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM