Reputation: 8755
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?
Upvotes: 2
Views: 867
Reputation: 23732
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.
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;
}
}
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:
Upvotes: 4