Welcome to my blog, hope you enjoy reading
RSS

Wednesday 6 February 2013

Comparable and Comparator Example to sort Objects


Comparable and Comparator Example to sort Objects

In Java, it’s very easy to sort an array or a list with primitive types. But you can also use Comperable and Comparator interfaces when you want to be able to short arrays or lists of your own custom objects.
Let’s begin with a very simple example using arrays of primitive types:
package com.javanotes2all.java.sorting;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
public class ObjectSortingExample {
public static void main(String[] args) {
int[] integerArray = {1,0,3,2};
Arrays.sort(integerArray);
System.out.println(Arrays.toString(integerArray));
String[] stringArray = {"J", "A", "V", "A", "C"};
Arrays.sort(stringArray);
System.out.println(Arrays.toString(stringArray));
List<String> stringList = new ArrayList<String>();
stringList.add("J");
stringList.add("A");
stringList.add("V");
stringList.add("A");
stringList.add("C");
Collections.sort(stringList);
for(String elem: stringList)
System.out.print(" "+elem);
}
}

output:

[0, 1, 2, 3]
[A, A, C, J, V]
 A A C J V


Now let’s try the same thing but with our own class.
Strudent.java
package com.javanotes2all.java.sorting;

public class Student 
{
 private int id;
 private String name;
 private int currentYearOfStudy;

public Student(int id,String name,int curYearOfStudy) {
 this.id = id;
 this.name = name;
 this.currentYearOfStudy = curYearOfStudy;
 }

 public int getId() {
  return this.id;
 }

 public String getName() {
  return this.name;
 }

 public int getCurrentYearOfStudy() {
  return this.currentYearOfStudy;
 }

}
ObjectSortingWithOurOwnClassExample.java
package com.javanotes2all.java.sorting;
import java.util.Arrays;
public class ObjectSortingWithOurOwnClassExample {

  public static void main(String[] args) {

   Student[] studentArray = new Student[3];
   studentArray[0] = new Student(1, "Nikos",1);
   studentArray[1] = new Student(5, "Ilias", 4);
   studentArray[2] = new Student(4, "Byron", 5);

   Arrays.sort(studentArray);
   System.out.println(Arrays.toString(studentArray));

 }
}

The output of this will be:

Exception in thread "main"java.lang.ClassCastException:
com.javanotes2all.java.sorting.Student cannot be cast to java.lang.Comparable
 at java.util.Arrays.mergeSort(Arrays.java:1157)
 at java.util.Arrays.sort(Arrays.java:1092)
 at com.javanotes2all.java.sorting.ObjectSortingWithOurOwnClassExample.main
(ObjectSortingWithOurOwnClassExample.java:14)

And that is completely reasonable because Arrays.sort method has no clue on how to compare my objects. Somehow we have to giveArrays.sort a mechanism on how to compare my objects. To do that, we simply implement the generic Comparable<E> interface and override the compareTo method.
Strudent1.java
package com.javanotes2all.java.sorting;

public class Student1  implements Comparable<Student1> {

 private int id;
 private String name;
 private int currentYearOfStudy;

 public Student1(int id, String name, int currYearOfStudy) {
  this.id = id;
  this.name = name;
  this.currentYearOfStudy = currYearOfStudy;
 }

 public int getId() {
  return this.id;
 }

 public String getName() {
  return this.name;
 }

 public int getCurrentYearOfStudy() {
  return this.currentYearOfStudy;
 }

 @Override
 public String toString() {
  return "[id=" + this.id + ", name=" + this.name
  + ", Current Year of Study=" + this.currentYearOfStudy + "]";
 }

 @Override
 public int compareTo(Student1 stud) {
  return (this.id - stud.id);
 }
}
ObjectSortingWithOurOwnClassExample1.java
package com.javanotes2all.java.sorting;

import java.util.Arrays;

public class ObjectSortingWithOurOwnClassExample1 
{
 public static void main(String[] args) {

  Student1[] studentArray = new Student1[3];
  studentArray[0] = new Student1(1, "abc",1);
  studentArray[1] = new Student1(5, "xyz", 4);
  studentArray[2] = new Student1(4, "pqr", 5);

  Arrays.sort(studentArray);
  System.out.println(Arrays.toString(studentArray));
 }
}
Now, as you might imagine, the Student will be sorted using the id field as a key. So the output of the above program would be:


[[id=1, name=abc, Current Year of Study=1]
, [id=4, name=pqr, Current Year of Study=5]
, [id=5, name=xyz, Current Year of Study=4]]
Now image that a client code “A” requires that Student objects can be sorted using the name as key and client code “B” requires thatStudent objects can be sorted using currentYearOfStudy. To do that we have to define different Comperators. We will do that inside the Student class but you can also create another separate class with your own Comperators.
Strudent2.java

package com.javanotes2all.java.sorting;

import java.util.Comparator;

public class Student2 implements Comparable<Student2> {

 private int id;
 private String name;
 private int currentYearOfStudy;

 public Student2(int id, String name, int currYearOfStudy) {
  this.id = id;
  this.name = name;
  this.currentYearOfStudy = currYearOfStudy;
 }

 public int getId() {
  return this.id;
 }

 public String getName() {
  return this.name;
 }

 public int getCurrentYearOfStudy() {
  return this.currentYearOfStudy;
 }

 @Override
 public String toString() {
 return "[id=" + this.id + ", name=" + this.name
  + ", Current Year of Study=" + this.currentYearOfStudy + "]";
 }

 @Override
 public int compareTo(Student2 stud) {
  return (this.id - stud.id);
 }

public static Comparator<Student2> idComperator = new Comparator<Student2>() {

  @Override
  public int compare(Student2 st1, Student2 st2) {
   return (int) (st1.getId() - st2.getId());
  }
 };

 public static Comparator<Student2> currentYearComperator = new Comparator<Student2>() {

  @Override
  public int compare(Student2 st1, Student2 st2) {
   return (int) (st1.getCurrentYearOfStudy() - st2.getCurrentYearOfStudy());
  }
 };

}
ObjectSortingWithOurOwnClassExample2.java
package com.javanotes2all.java.sorting;
import java.util.Arrays;
public class ObjectSortingWithOurOwnClassExample2 
{
 public static void main(String[] args) {

 Student2[] studentArray = new Student2[3];
 studentArray[0] = new Student2(1, "abc",1);
 studentArray[1] = new Student2(5, "xyz", 4);
 studentArray[2] = new Student2(4, "abc", 5);

 Arrays.sort(studentArray, Student2.idComperator);
 System.out.println("Using id as key :"+ Arrays.toString(studentArray));

 Arrays.sort(studentArray, Student2.currentYearComperator);
 System.out.println("Using Current Year of Study as key :"+Arrays.toString(studentArray));

 }
}

The output of this program will be:
Using id as key :[[id=1, name=abc, Current Year of Study=1], [id=4, name=abc, Current Year of Study=5], [id=5, name=xyz, Current Year of Study=4]]
Using Current Year of Study as key :
[[id=1, name=abc, Current Year of Study=1], 
[id=5, name=xyz, Current Year of Study=4], 
[id=4, name=abc, Current Year of Study=5]]
Of course you can further customize your Comperator and make it more complex. For example we will make a Comperator that will sort our objetc first by currentYearOfStudy and then by name:
Strudent3.java
package com.javanotes2all.java.sorting;

import java.util.Comparator;

public class Student3 implements Comparable<Student3> {

 private int id;
 private String name;
 private int currentYearOfStudy;

 public Student3(int id, String name, int currYearOfStudy) {
  this.id = id;
  this.name = name;
  this.currentYearOfStudy = currYearOfStudy;
 }

 public int getId() {
  return this.id;
 }

 public String getName() {
  return this.name;
 }

 public int getCurrentYearOfStudy() {
  return this.currentYearOfStudy;
 }

 @Override
 public String toString() {
 return "[id=" + this.id + ", name=" + this.name
  + ", Current Year of Study=" + this.currentYearOfStudy + "]";
 }

 @Override
 public int compareTo(Student3 stud) {
  return (this.id - stud.id);
 }

public static Comparator<Student3> idComperator = new Comparator<Student3>() {

  @Override
  public int compare(Student3 st1, Student3 st2) {
   return (int) (st1.getId() - st2.getId());
  }
 };

 public static Comparator<Student3> currentYearComperator = new Comparator<Student3>() {

  @Override
  public int compare(Student3 st1, Student3 st2) {
   return (int) (st1.getCurrentYearOfStudy() - st2
     .getCurrentYearOfStudy());
  }
 };

 public static Comparator<Student3> currentYearandNameComperator = new Comparator<Student3>() {

  @Override
  public int compare(Student3 st1, Student3 st2) {
   int retval = (int) (st1.getCurrentYearOfStudy() - st2.getCurrentYearOfStudy());
   if (retval == 0) {
    retval = (int) (st1.getName().compareTo(st2.getName()));
   }
   return retval;
  }
 };

}

ObjectSortingWithOurOwnClassExample3.java
package com.javanotes2all.java.sorting;

import java.util.Arrays;

public class ObjectSortingWithOurOwnClassExample3 {

 public static void main(String[] args) {

  Student3[] studentArray = new Student3[3];
  studentArray[0] = new Student3(1, "Nikos",5);
  studentArray[1] = new Student3(5, "Ilias", 4);
  studentArray[2] = new Student3(4, "Byron", 4);

 Arrays.sort(studentArray, Student3.currentYearandNameComperator);
System.out.println("Using Current Year and Name as key :"+ Arrays.toString(studentArray)); 
 }
}

The output of this program will be:
Using Current Year and Name as key :[[id=4, name=Byron, Current Year of Study=4], [id=5, name=Ilias, Current Year of Study=4], [id=1, name=Nikos, Current Year of Study=5]]

0 comments: