I'm trying to achieve the common "Top X Points" in LINQ.
class member {
public string name {get;set;}
public int point {get;set;}
}
An instance array similar to the one shown in
var SelectedMembers = AllMembers
.OrderByDescending(mem=>mem.Point)
.Take (100);
Then, if there are many people with the same points, I don't think it can be extracted correctly.
This is the order of common points
1.AAA
2.BBB
2. CCC
4.DDD
4.EEE
4.FFF
As shown in , how can I extract more than a specified number of people and make a group list with the same points in mind?
If the number of points is counted as high as +1, the number of points will be ranked.
varq1=AllMembers.OrderByDescending(m=>m.Point).Select(m)=>
new
{
Point = m.Point,
Name = m.Name,
// You can check the ranking by counting the top number of points as they are
Rank=AllMembers.Count(m2=>(m2.Point>m.Point))+1
}).Where(ano=>ano.Rank<=4);
foreach (varano in q1)
{
Console.WriteLine(string.Format("Rank={0}\tPoint={1}\tName={2}",ano.Rank,ano.Point,ano.Name));
}
Alternatively, the Nth Point will be ranked Nth by arranging the points in descending order without considering duplication, so try to reduce the calculation a little by checking the points first.
var po=AllMembers.OrderByDescending(m2=>m2.Point).Skip(4-1).FirstOrDefault().Point;
varq2=AllMembers.Where(m=>m.Point>=po).OrderByDescending(m=>m.Point).Select(m)=>
new
{
Point = m.Point,
Name = m.Name,
Rank=AllMembers.Count(m2=>(m2.Point>m.Point))+1
});
You can do that.
If you only do LINQ, it's either unreasonable to hold the condition or increase the amount of calculation, so you should use foreach
normally.
intrank=0, count=0, prev=-1;//← Set the initial value to an unlikely value as Point
foreach(varmin AllMembers.OrderByDescending(_=>_.Point))
{
count++;
if(m.Point!=prev)
{
if (count > 100)
{
break;
}
rank=count;
}
prev = m.Point;
Console.WriteLine("{0,-3}{1,-3}{2}{3}", count, rank, m.Name, m.Point);
}
If you want to increase the LINQ portion more, overload the indexer.
intrank=0,prev=-1;
AllMembers.OrderByDescending(_=>_.Point)
.Select(m,i)=>new
{
Rank=prev==(prev=m.Point)?rank:(rank=i+1),
Value = m
})
.Where(_=>_.Rank<=100);
You can also write
If the other party is an ORM such as EntityFramework
,
var threshold=AllMembers.OrderByDescending(_=>_.Point)
.Take (100)
.Min(_=>(int?)_.Point);
AllMembers.Where(_=>_.Point>=threshold);
I think a policy like this would be good.
The ranking matches "How many people are above you +1", so you can do it by looking at each ranking.
var ranking = AllMembers
.OrderByDescending(_=>_.Point)
.GroupBy(_=>_.Point)
.Select(group=>new
{
Rank=AllMembers.Count(_=>_.Point>group.Key) +1,
Members=group
});
// Ranking.Where(_=>_.Rank<=4) if you want to extract 4th or higher.
If you add the number of people in order from the top to the top, you just need to count the same ranking, but I think it's troublesome to do this with standard LINQ without using foreach.
For example, if you use Rx or Ix Scan()
, you can write like this.
var ranking=list
.OrderByDescending(_=>_.Point)
.GroupBy(_=>_.Point)
.Scan(new)
{
Rank = 1,
Members = new List <Member > ( )
},
(prev, group) = > new
{
Rank=prev.Rank+prev.Members.Count(),
Members=group.ToList()
});
var members=new Member[]
{
new Member() {Name="H", Point=1} ,
new Member() {Name="G", Point=1} ,
new Member() {Name="F", Point=2},
new Member() {Name="E", Point=2},
new Member() {Name="D", Point=3},
new Member() {Name="C", Point=3},
new Member() {Name="B", Point=4},
new Member() {Name="A", Point=4},
};
var threshold = 5;
var result=members
.OrderByDescending(x=>x.Point)
.Select ((Value,Index)=>new {Value,Index})
.GroupBy(x=>x.Value.Point)
.Select(x=>new{Rank=x.First().Index+1, Items=x.Select(y=>y.Value)})
.Where(x=>x.Rank<=threshold);
foreach(var group in result)
{
Console.WriteLine(group.Rank.ToString());
foreach(varitem in group.Items.OrderBy(x=>x.Name))
{
Console.WriteLine(item.Name+item.Point);
}
}
Console.ReadLine();
You can do it by dividing the LINQ into two and using TakeWhile.
var AllMembers=new[]{
new {Name="AAA", Point=1} ,
new {Name="BBB", Point=2},
new {Name="CCC", Point=2},
new {Name="DDD", Point=4},
new {Name="EEE", Point=4},
new {Name="FFF", Point=4}
};
varSortedMembers=
AllMembers.OrderByDescending(m=>m.Point).ToArray();
// take up to a designated number of people
// (Even if the designated number of people is reached, if there is a member with the same point, take it out.)
varSelectedMembers=
SortedMembers.TakeWhile(m,i)=>i<4||m.Point==SortedMembers[i-1].Point);
Console.WriteLine(string.Join(Environment.NewLine, SelectedMembers)));
613 GDB gets version error when attempting to debug with the Presense SDK (IDE)
578 Understanding How to Configure Google API Key
918 When building Fast API+Uvicorn environment with PyInstaller, console=False results in an error
573 rails db:create error: Could not find mysql2-0.5.4 in any of the sources
© 2024 OneMinuteCode. All rights reserved.