I want to group students with similar scores with 5 points up/ down.
public class Students
{
public string Name {get; set;}
public int Marks {get; set;}
public int GroupID {get; set;}
}
public static void Main()
{
List<Students> students = new List<Students>();
students.Add(new Students { Name = "Aakash", Marks=89, GroupID=0 });
students.Add(new Students { Name = "Prakash", Marks=85, GroupID=0 });
students.Add(new Students { Name = "Ramesh", Marks=40, GroupID=0 });
students.Add(new Students { Name = "Neha", Marks=95, GroupID=0 });
students.Add(new Students { Name = "Suresh", Marks=93, GroupID=0 });
}
Expected Output:
GroupID 1:
Aakash, Prakash
Group 2:
Ramesh
GroupID 3:
Neha, Suresh
Any help is appreciated. Thanks.
Update:
What happens when students with marks of 4, 8, 12, 16, 20 & 24?
Ans: They would be different groups like this- 4 & 8 in Group 1, 12 & 16 in Group 2 and 20 & 24 in Group 3.
CodePudding user response:
If you want to determine the range of marks for each group based on the highest mark in that group, you may write something like this:
var ordered = students.OrderByDescending(s => s.Marks).ToList();
int groupId = 0;
int nextIndex = 0;
while (nextIndex < ordered.Count)
{
groupId ;
var firstInGroup = ordered[nextIndex];
var group = ordered.Skip(nextIndex).
TakeWhile(s => firstInGroup.Marks - s.Marks <= 5).ToList();
group.ForEach(s => s.GroupID = groupId);
nextIndex = group.Count;
}
To make this reusable and to allow grouping to happen in either direction, you can turn this into a helper method like so:
enum MarkGroupingOption { HighestToLowest, LowestToHighest }
static void SetGroupIds(List<Students> students, int marksThreshold,
MarkGroupingOption groupingOption)
{
var ordered = (groupingOption == MarkGroupingOption.HighestToLowest
? students.OrderByDescending(s => s.Marks).ToList()
: students.OrderBy(s => s.Marks).ToList());
int groupId = 0;
int nextIndex = 0;
while (nextIndex < ordered.Count)
{
groupId ;
var firstInGroup = ordered[nextIndex];
var remaining = ordered.Skip(nextIndex);
var group = (groupingOption == MarkGroupingOption.HighestToLowest
? remaining.TakeWhile(s => firstInGroup.Marks - s.Marks <= marksThreshold)
: remaining.TakeWhile(s => s.Marks - firstInGroup.Marks <= marksThreshold)
).ToList();
group.ForEach(s => s.GroupID = groupId);
nextIndex = group.Count;
}
}
Usage:
SetGroupIds(students, 5, MarkGroupingOption.HighestToLowest);
SetGroupIds(students, 5, MarkGroupingOption.LowestToHighest);