Java Sorting Objects with Multiple Parameters

Go To StackoverFlow.com

4

I have recently been working to better my understanding of sorting algorithms and their relationship to different types of input. Currently, I'm working on a Student Management program where each student has three parameters: Last Name, GPA, and User ID (String, double, int). They are each stored in a Student class with those three parameters, and there are DOZENS of students (a key feature of the program is to input, remove, and update students).

My question is: using the major sorting algorithms (mergesort, quicksort, etc.), what is the best way to sort my list of students by each parameter? For instance, what is the best way to perform a mergesort to sort the list by GPA? Or to use quicksort to sort the list by last name?

Essentially my question boils down to...I can sort these objects if they didn't have three parameters (writing a mergesort to sort 100 numbers is very easy for me). How do I manage the other two parameters and make sure they're accessible after the sort?

2012-04-04 17:44
by BennyMathison
Is this homework - Louis Wasserman 2012-04-04 17:46
The homework assignment (due weeks ago) was to learn how to hardcode a mergesort to sort a list of 100 integers. I'm just trying to learn the limits of the Java tools for when I start working on much larger projects - BennyMathison 2012-04-04 17:48


5

The way this is done in Java is to use different Comparators. Then you say:

Collections.sort(list, new NameComparator());

Or

Collections.sort(list, new GpaComparator());

These comparators use different fields to define the order between two elements.

For example, Name Comparator might be:

class NameComparator implements Comparator< Student> {
    @Override public int compare(Student left, Student right) {
        return left.getName().compareTo(right.getName());
    }
}

And GpaComparator might 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;
     }
 }
2012-04-04 17:49
by daveb
A better way to write the GPAComparator is to use Integer objects instead of primitives and just delegate to the .compare() method on them. Then that if/elseif/else block becomes a single line - NoName 2012-04-04 18:29


1

I would recommend implementing the Comparable interface 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 a built-in sort like

List<Student> list = new ArrayList<Student>();
...
Collections.sort(list);

Or you can not implement Comparable and design 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 the other Collection's sort method

Collections.sort(list, MyComparator);
2012-04-04 17:48
by twain249
Comparable only works if you're sorting by the same thing every time - Louis Wasserman 2012-04-04 17:49
@LouisWasserman true I'll clarif - twain249 2012-04-04 17:50


1

The typical way to do this is to write a generic sorting algorithm on any type that accepts a Comparator, and then to write different Comparators to sort by different fields.

2012-04-04 17:49
by Louis Wasserman


1

This is probably off topic, but if you want to try something cool, the JDK 8 Lambda Preview offers a few 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 collection 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, supposing Jedi has method that behaves as 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 could be used as follows to generate a comparator by 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
2012-04-04 18:18
by Edwin Dalorzo
+1: Very cool way to go about comparators. I imagine we will see something like this deeply integrated soon. Very easy to use - BennyMathison 2012-04-05 01:42
@Mathew as a matter of fact you can give it try just now by downloading and installing the preview I shared above :- - Edwin Dalorzo 2012-04-05 02:31


0

It's really no different than sorting numbers, except that in this case your "digits" are the three fields of your users, the value of each digit is constrained by the values of each field, and the order of the fields determines the sort ranking.

To be a bit more specific, you have a Tupple with 3 fields: <GPA, Last Name, User ID>, and lets assume that you want to sort by GPA, and then Last Name, and the User ID.

In the same way that 219 is sorted above 139 (ie. the "hundreds" digit has a higher value even though the "tens" digit is lower), a tupple like <3.75, Jones, 5> will be sorted above <3.0, Adams, 2> because the "GPA digit" (which is more significant) has a higher value, even though the "last name digit" is lower (eg. Jones is "lower" than Adams).

2012-04-04 17:48
by cdeszaq


0

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
        };
    }
}
2015-06-30 08:08
by ravi ranjan
Ads