Reputation: 3231
I have the table as follow in my database:
User Table
UserID
Name
Point
What i intend to do:
| Rank | Name | Point |
| 344 | UserA | 2000 |
| 345 | UserB | 1500 |
| 345 | UserC | 1500 |
| 347 | UserD | 1200 |
| 348 | UserE | 1000 |
| 349 | UserF | 1000 | <-- targeted user
| 350 | UserG | 900 |
| 350 | UserH | 800 |
| 352 | UserI | 700 |
| 353 | UserJ | 600 |
What i have tried:
int point = 1000;
var top6 = db.User.Where(p => p.Point >= point).OrderBy(p => p.Point).Take(6);
var bottom4 = db.User.Where(p => p.Point < point).OrderByDescending(p => p.Point).Take(4);
var leaderboard = top6.Union(bottom4).OrderByDescending(p => p.Point);
What is the outcome currently?
| Name | Point |
| UserA | 2000 |
| UserB | 1500 |
| UserC | 1500 |
| UserD | 1200 |
| UserE | 1000 |
| UserF | 1000 | <-- targeted user
| UserG | 900 |
| UserH | 800 |
| UserI | 700 |
| UserJ | 600 |
What still unsolved?
What is the problem I having? - Do not know how to assign global ranking to the user. - Do not know how to resolve tie condition to the rank. when tie, the rank should be same
Upvotes: 0
Views: 1004
Reputation: 23945
//EDIT: Linqpad Instant Share to reproduce it: http://share.linqpad.net/urtpc9.linq
I've gone a slightly different approach to shree.pat18. Instead of generating a list and zipping it, I've used the overloaded Select()
method to generate an index, after grouping the results, to deal with Tie in points.
Code from LinqPad:
void Main()
{
var players = new List<Player>()
{
new Player() {Name ="UserA", Points=2500},
new Player() {Name ="UserB", Points=2400},
new Player() {Name ="UserC", Points=2300},
new Player() {Name ="UserD", Points=2200},
new Player() {Name ="UserE", Points=2100},
new Player() {Name ="UserF", Points=2000},
new Player() {Name ="UserG", Points=1900},
new Player() {Name ="UserH", Points=1800},
new Player() {Name ="UserI", Points=1800},
new Player() {Name ="UserJ", Points=1700},
new Player() {Name ="UserK", Points=1600},
new Player() {Name ="UserL", Points=1500},
new Player() {Name ="UserN", Points=1300},
new Player() {Name ="UserM", Points=1300},
};
var TargetPoints = 1000;
var RankedPlayers = players.OrderByDescending(p => p.Points)
.GroupBy (p => p.Points)
.Select ((grp, i) => new {
Rank = i,
Players = grp.OrderByDescending (g => g.Name)
})
.Dump();
}
public class Player
{
public string Name { get; set; }
public int Points { get; set; }
}
Output in LinqPad:
Upvotes: 1
Reputation: 21757
Try this:
int point = 1000;
var ranks = Enumerable.Range(1,db.User.Count);
var result = db.User.OrderByDescending(x => x.points).ThenBy(x => x.Name).Zip(ranks, (x,y) => new {x.Name, x.Point, rank = y});
var top6= result.Where(x => x.Point>= point).OrderBy(x => x.Point).Take(6);
var bottom4 = result.Where(x => x.Point< point).OrderByDescending(x => x.Point).Take(4);
var leaderboard = top6.Union(bottom4).OrderByDescending(x => x.Point).ThenBy(x => x.Name);
Start by generating an ordered list, which we will use as our global ranks. Zip it with the appropriately ordered list of users. The output of the zipping step is a collection of anonymous objects which include a rank field. Then, just use the returned collection along with your logic to get the top, bottom and combined results.
Upvotes: 0