How do I sort and rank the parent list by comparing the child list elements using java?

93 Views Asked by At

I need to find the Students ranks based on the subjectPriorityOrder given. Student list contains subject list with marks. Subject Priority Order list has the priority order which one we should have to give a first priority, 2nd, 3rd and so on [MATHS, ENGLISH, SCIENCE, COMPUTER]

Student.java

private Long id;
private String firstName;
private String lastName;
private List<Subject> subjects;

Subject.java

private String name;
private Integer marks;

Input - Student List

[
{"id": 1,"firstName": "Alice", "lastName": "Alice",
        "subjects": [
            {"name": "SCIENCE", "marks": 50},
            {"name": "MATHS", "marks": 45}]},
{"id": 2,"firstName": "Bob", "lastName": "Bob",
        "subjects": [
            {"name": "MATHS", "marks": 80},
            {"name": "ENGLISH", "marks": 85}
        ]},
{"id": 3, "firstName": "John","lastName": "John",
        "subjects": [
            {"name": "MATHS", "marks": 80},
            {"name": "SCIENCE", "marks": 45},
            {"name": "ENGLISH", "marks": 75}
        ]},
{"id": 4,"firstName": "Thomas","lastName": "Thomas",
        "subjects": [
            {"name": "MATHS", "marks": 90}
        ]}
]

Expected Output Details:

If any of the student has highest marks in Maths, we need to put 1st rank to that student.

If two students (StudentA & StudentB ) have same marks in Maths and StudentB has highest marks in English, we need to put 1st Rank to StudentB and 2nd Rank to StudentA

Tried scenario:

I have written the code to sort the student list based on the priority order given.

But I don't know how to compare the marks for each subject with respect to the studentList (one student with other student).

How should I write the Comparator for each Subjects and sort the student list by comparing one student subject wise marks with other student's subject wise marks.

Kindly help me to complete this sorting.

The below code sorting the student list by subjectPriorityOrder and it is not comparing the marks.

List<String> subjectPriorityOrder = Arrays.asList("MATHS", "ENGLISH", "SCIENCE", "COMPUTER", "HISTORY");

public List<Student> sortStudentList(List<Student> studentList, List<String> subjectPriorityOrder) {
        if (studentList != null && !studentList.isEmpty() && subjectPriorityOrder != null && !subjectPriorityOrder.isEmpty()) {
            List<Student> sortedList = new ArrayList<>();
            List<Student> unSortedList = new ArrayList<>();
            unSortedList.addAll(studentList);
            Integer studentRank = 0;
            for (String subjectName : subjectPriorityOrder) {
                for (Iterator<Student> studentIterator = studentList.iterator(); studentIterator.hasNext(); ) {
                    Student student = studentIterator.next();
                    Subject subject = getSubjectIfFound(student.getBenefitValues(), subjectName); // search for the item on the list by subjectName
                    if (subject != null) {
                        LOGGER.info("####### Matched Student ID ######## {}", student.getId());
                        //student.setRank(++studentRank); TODO: Need to set a rank after comparing the marks
                        sortedList.add(student);       // if found add to sorted list
                        //unSortedList.remove(student);
                        studentIterator.remove();      // remove added item from iterator
                        studentList.remove(student);      // remove the added item from the studentList
                        LOGGER.info("-----------------------------------------------------------------");
                    }
                }
            }
            sortedList.addAll(studentList);        // append the remaining items on the unsorted list to new sorted list
            return sortedList;
        } else {
            return studentList;
        }
    }

    private Subject getSubjectIfFound(List<Subject> subjectMarks, String subjectName) {
        for (Subject subject : subjectMarks) {
// TODO: Need to compare marks as well
            if (subject.getName().equals(subjectName)) {
                return subject;
            }
        }
        return null;
    }
1

There are 1 best solutions below

4
BIBOO nation On
public class Subject {
    String name;
    Integer marks;

    public Subject(String name, Integer marks) {
        this.name = name;
        this.marks = marks;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Integer getMarks() {
        return marks;
    }

    public void setMarks(Integer marks) {
        this.marks = marks;
    }

    @Override
    public String toString() {
        return "Subject{" +
                "name='" + name + '\'' +
                ", marks=" + marks +
                '}';
    }
}


import java.util.List;

public class Student {
    Long id;
    List<Subject> subjects;

    public Student(Long id, List<Subject> subjects) {
        this.id = id;
        this.subjects = subjects;
    }

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public Integer getSubjectGrade(String subject) {
        for (final var sub : subjects) {
            if (sub.getName().equals(subject)) {
                return sub.getMarks();
            }
        }
        return 0;
    }

    public List<Subject> getSubjects() {
        return subjects;
    }

    public void setSubjects(List<Subject> subjects) {
        this.subjects = subjects;
    }

    @Override
    public String toString() {
        return "Student{" +
                "id=" + id +
                ", subjects=" + subjects +
                '}';
    }
}


import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;

public class Main {
    public static void main(String[] args) {
        final var alice = new Student(1L, List.of(new Subject("SCIENCE", 50), new Subject("MATHS", 45)));
        final var bob = new Student(2L, List.of(new Subject("MATHS", 80), new Subject("ENGLISH", 85)));
        final var john = new Student(3L, List.of(new Subject("MATHS", 80), new Subject("SCIENCE", 45), new Subject("ENGLISH", 75)));
        final var thomas = new Student(4L, List.of(new Subject("MATHS", 90)));

        final var students = new ArrayList<>(List.of(alice, bob, john, thomas));
        System.out.println(students);
        System.out.println(students.stream().sorted(new StudentSubjectComparator()).toList());
    }
}

class StudentSubjectComparator implements Comparator<Student> {
    private static final String[] SubjectPriority = {"MATHS", "ENGLISH", "SCIENCE", "COMPUTER"};

    @Override
    public int compare(Student o1, Student o2) {
        for (final var subject : SubjectPriority) {
            int comparison = o1.getSubjectGrade(subject).compareTo(o2.getSubjectGrade(subject));
            if (comparison == 0) {
            } else {
                return -comparison; // note the negative sign. This is what sorts in reverse order (descending)
            }
        }
        return 0;
    }
}

This is the sample code I have written. There are many improvements that can be made, such as having Subject as an Enum, and then having subjects as a Map of <Subject, Integer>.

As for the comparator I have written, you can see that it defines an internal subject priority, and based on the priority it gets a students grades. Based on your comment, I have written a method getSubjectGrade(String subject) that gets a grade of a subject if it exist, defaulting to zero if not.

I then return the comparison if the two students do not have the same grades, else I continue to compare the students grades. There is room for further improvement, such as having the comparator have a dynamic internal subject priority but I wont go further.

Output:

[Student{id=1, subjects=[Subject{name='SCIENCE', marks=50}, Subject{name='MATHS', marks=45}]}, Student{id=2, subjects=[Subject{name='MATHS', marks=80}, Subject{name='ENGLISH', marks=85}]}, Student{id=3, subjects=[Subject{name='MATHS', marks=80}, Subject{name='SCIENCE', marks=45}, Subject{name='ENGLISH', marks=75}]}, Student{id=4, subjects=[Subject{name='MATHS', marks=90}]}]
[Student{id=4, subjects=[Subject{name='MATHS', marks=90}]}, Student{id=2, subjects=[Subject{name='MATHS', marks=80}, Subject{name='ENGLISH', marks=85}]}, Student{id=3, subjects=[Subject{name='MATHS', marks=80}, Subject{name='SCIENCE', marks=45}, Subject{name='ENGLISH', marks=75}]}, Student{id=1, subjects=[Subject{name='SCIENCE', marks=50}, Subject{name='MATHS', marks=45}]}]