Home > Blockchain >  Group students with similar scores (5 points up/ down)
Group students with similar scores (5 points up/ down)

Time:08-20

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);
  • Related