0

I struggle to get a ranking place of a user in a list.

My list looks like this:

User Score
1 10
2 10
1 5
3 5
2 40
1 10

I try to get the ranking of user 3.

To do it I do a first linq request with group by user id.

And then I do a request to sum the scores(nbpoints) and orderby descending like this I have:

User 2 with 50 points User 1 with 25 points User 3 with 5 points

Then how can I get the ranking of the user? I tried the index with the select but it takes the index before the sorting.

My request is below:

 MyScoreRankObject = users.Select((u, index) =>
                  {
                      return new StatResultDto
                      {
                          ActualScore = u.Sum(s => s.NbPoints),
                          Index = u.Index
                    };
                  }).OrderByDescending(s => s.ActualScore).Where(u => u.Id ==3).FirstOrDefault();

How can I do it to get the raniking?

I try to get:

Request for user 3 gives me the object:

new StatResultDto
                      {
                          ActualScore = u.Sum(s => s.NbPoints),
                          Index = u.Index // Gives the ranking
                    };

Thanks,

Nguyễn Văn Phong
  • 13,506
  • 17
  • 39
  • 56
dalton5
  • 915
  • 2
  • 14
  • 28
  • Does this answer your question? [How to get the index of an item in a list in a single step?](https://stackoverflow.com/questions/17995706/how-to-get-the-index-of-an-item-in-a-list-in-a-single-step) – daremachine Mar 07 '21 at 02:25

2 Answers2

0

I found a solution for others who struggle. Not sure the best one. If you have better I take. I added this code after the order by.

.Select((u, index) =>
                  {
                      u.Rank = index + 1;
                      return u;
                  })

Final solution:

 MyScoreRankObject = users.Select((u) =>
              {
                  return new StatResultDto
                  {
                      ActualScore = u.Sum(s => s.NbPoints)
                };
              }).OrderByDescending(s => s.ActualScore).Select((u, index) =>
                  {
                      u.Rank = index + 1;
                      return u;
                  }).Where(u => u.Id ==3).FirstOrDefault();
dalton5
  • 915
  • 2
  • 14
  • 28
0

Demo on dotnetfiddle

Actually, you just GroupBy then OrderByDescending.

var groupByandSortedData = myData.GroupBy(r => r.UserId)
                            .Select(g => new { User = g.Key, ActualScore = g.Sum(s => s.NbPoints) })
                            .OrderByDescending(p => p.ActualScore);

Finally, you can get your data by ranking with 3 ways like below:

var ranking = 3;
Console.WriteLine(groupByandSortedData.Skip(2).FirstOrDefault());
Console.WriteLine(groupByandSortedData.ElementAtOrDefault(ranking-1));  // due to index starting from 0 
Console.WriteLine(groupByandSortedData.ToList()[ranking-1]);

Output

{ User = 3, ActualScore = 5 }
{ User = 3, ActualScore = 5 }
{ User = 3, ActualScore = 5 }

In terms of Performance

I would prefer the 1st & 2nd way over the 3rd one. Because the last way has been executed all data & load to memory insead.

Nguyễn Văn Phong
  • 13,506
  • 17
  • 39
  • 56
  • Thanks for the reponse but I don't want to get the third. I want to know user 3 is which ranking. – dalton5 Mar 07 '21 at 19:44