Java sorting objects with multiple parameters
I recently worked on improving my understanding of sorting algorithms and their relationship to different input types. I am currently working on a student management program where each student has three parameters: Last Name, VGU and User ID (String, double, int). Each of them is stored in the Student class with these three parameters, and there are DOSE of students (the key feature of the program is to enter, delete and update students).
My question is, using basic sorting algorithms (mergesort, quicksort, etc.) what is the best way to sort my list of students by each parameter? For example, what is the best way to perform a join to sort the list by GPA? Or use quicksort to sort the list by last name?
Basically my question boils down to ... I can sort these objects if they didn't have three parameters (it's very easy for me to write a merge to sort 100 numbers). How do I manage the other two parameters and make sure they are available after sorting?
source to share
As it is done in Java, you need to use different Comparators . Then you say:
Collections.sort(list, new NameComparator());
or
Collections.sort(list, new GpaComparator());
These comparators use different fields to determine the order between two elements.
For example, a Name Comparator could be:
class NameComparator implements Comparator< Student> {
@Override public int compare(Student left, Student right) {
return left.getName().compareTo(right.getName());
}
}
And the GpaComparator can be
class GpaComparator implements Comparator< Student> {
@Override public int compare(Student left, Student right) {
if (left.getGpa() < right.getGpa()) {
return -1;
} else if (left.getGpa() > right.getGpa()) {
return 1;
} else {
return 0;
}
}
source to share
I would recommend to implement the interface Comparable
in your Student
class like this
public class Student implements Comparable {
public int compareType; //you can make this an enum if you want
...
public int compareTo(Object o) {
if(compareType == 0)
return gpaCompareTo(o);
else if(compareType == 1)
return nameCompareTo(o);
return idCompateTo(o);
}
public int gpaCompareTo(Object o) {
//implement your gpaCompareTo
}
public int nameCompareTo(Object o) {
//implement your nameCompareTo
}
public int idCompareTo(Object o) {
//implement your idCompareTo
}
}
And then use an inline view like
List<Student> list = new ArrayList<Student>();
...
Collections.sort(list);
Or you cannot implement Comparable
and create your own comparators
public class MyComparator implements Comparator<Student> {
public int compare(Student o1, Student o2) {
//implement the comparator
}
public boolean equals(Object o) {
//implement the equals
}
}
Then you can use another sorting method Collection's
Collections.sort(list, MyComparator);
source to share
The typical way to do this is to write a general sorting algorithm for any type that accepts Comparator
, and then write different ones Comparator
to sort on different fields.
source to share
This is probably off-topic, but if you want to try something cool, the JDK 8 Lambda Preview offers some cool ways to define comparators using Lamda expressions and method references .
Let's say we have a class:
class Jedi {
private final String name;
private final int age;
//...
}
And then a set of them:
List<Jedi> jediAcademy = asList(new Jedi("Obiwan",80), new Jedi("Anakin", 30));
sort(jediAcademy, (j1, j2) -> j1.getAge() > j2.getAge() ? 1 : j1.getAge() < j2.getAge() ? -1 : 0);
System.out.println(jediAcademy); //Anakin, Obiwan
Or with method references if Jedi has a method that behaves like a comparator (same signature)
class Jedi {
public static int compareByAge(Jedi first, Jedi second){
return first.age > second.age ? 1 : first.age < second.age ? -1 : 0;
}
//...
}
Which can be used as follows to create a comparator using a method reference:
List<Jedi> jediAcademy = asList(new Jedi("Obiwan",80), new Jedi("Anakin", 30));
sort(jediAcademy, Jedi::compareByAge);
System.out.println(jediAcademy);//Anakin, Obiwan
source to share
This is really nothing more than a sorting of numbers, except that in this case your "numbers" are your users' three fields, the meaning of each digit is limited to the values of each field, and the order of the fields is determined by the sort.
To be more specific, you have a Tupple with three fields: <GPA, Last Name, User ID>
and lets assume you want to sort by GPA and then by Last Name and User ID.
In the same way that 219 is sorted above 139 (i.e. the "hundreds" digit is higher, even if the "tens" is lower), a scoreboard like this <3.75, Jones, 5>
will be sorted higher <3.0, Adams, 2>
because the "GPA" digit (which is more significant ) has a higher value even if the "family number" is lower (for example, Jones is "lower" than Adams).
source to share
Use multiple comparators
class Student
{
String lastName;
dounle GPA;
int userId
static Comparator<Student> getStudentLastNameComparator() {
return new Comparator<Student>() {
@Override
public int compare(Student Student1, Student Student2) {
return Student1.getlastName().compareTo(Student2.getlastName());
}
// compare using Student lastName
};
}
static Comparator<Student> getStudentGPAComparator() {
return new Comparator<Student>() {
@Override
public int compare(Student Student1, Student Student2) {
if(Student1.GPA < Student2.GPA)
return 1;
else
return -1;
}
// compare using Student GPA
};
}
static Comparator<Student> getStudentUserIdComparator() {
return new Comparator<Student>() {
@Override
public int compare(Student Student1, Student Student2) {
if(Student1.userId < Student2.userId)
return 1;
else
return -1;
}
// compare using Student userId
};
}
}
source to share