Sorting collections of user-defined objects in Java

Posted on 29th March 2021

A Collection is a group of objects that can be of homogenous data type or heterogeneous data type. Homogeneous means same data type and Heterogenous means different data types. A class is a heterogeneous data type because it can contain different data types like int, double, String and may also contain other classes. There are different types of collections in Java - ArrayList, TreeSet, HashSet, HashTable are a few example. The java.util.Collections contains methods to perform various operations on a collection. One of those methods is the sort method which sorts the elements of a collection in ascending order. For example, to sort a collection of strings,

// Defind a collection of string
ArrayList<String> fruits = new ArrayList<String>();

// Add elements to the collection
fruits.add("Grapes");
fruits.add("Orange");
fruits.add("Apple");
fruits.add("Cherry");

// Sort
Collections.sort(fruits);

// Print all elements
for (String fruit : fruits)
    System.out.printf("%s ", fruit);
Apple Cherry Grapes Orange

Sorting a collection of user-defined objects

Consider a class named Part which consists of the attributes, number and name.

public class Part {
   int number;
   String name;

   public Part(int number, String name) {
      this.number = number;
      this.name = name;
   }
}

Create a collection of Part objects and try calling the sort method.

ArrayList<Part> partsList = new ArrayList<Part>();

partsList.add(new Part(19500, "Brake Pads"));
partsList.add(new Part(11502, "Wiper Blade"));
partsList.add(new Part(18021, "Abs Sensor"));
partsList.add(new Part(14235, "Ignition Lead"));
Collections.sort(partsList);

The following error is thrown when you compile this code

java: no suitable method found for sort(java.util.ArrayList<Part>)
    method java.util.Collections.sort(java.util.List<T>) is not applicable
      (inference variable T has incompatible bounds
        equality constraints: Part
        lower bounds: java.lang.Comparable<? super T>)
    method java.util.Collections.<T>sort(java.util.List<T>,java.util.Comparator<? super T>) is not applicable
      (cannot infer type-variable(s) T
        (actual and formal argument lists differ in length))

This is because, the sort method expects the list that is passed to implement the Comparable interface in its class.

The comparable interface is used to sort user-defined class objects and it contains a single method

int compareTo(T obj)

The compareTo method compares this(current) object with the object that is specified. It returns,

  • a negative integer value if this object is less than specified object.
  • zero, if the objects are equal.
  • a positive integer if the current object is greater.

Here is how to implement Comparable on the Part class to compare the Part names. The String data type already has a compareTo method to compare two strings, so this can be used in the compareTo method for the Parts.

public class Part implements Comparable<Part> {
   int number;
   String name;

   public Part(int number, String name) {
      this.number = number;
      this.name = name;
   }
  
  @Override
   public int compareTo( Part p){
      return name.compareTo(p.name);
   }

}

Now you can call the Collections.sort method to sort the parts in ascending order.

ArrayList<Part> partsList = new ArrayList<Part>();

partsList.add(new Part(19500, "Brake Pads"));
partsList.add(new Part(11502, "Wiper Blade"));
partsList.add(new Part(18021, "Abs Sensor"));
partsList.add(new Part(14235, "Ignition Lead"));

// Sort
Collections.sort(partsList);

// Print
for (Part p : partsList)
   System.out.println("[" + p.number + " " + p.name + "]");

Outputs

[18021 Abs Sensor]
[19500 Brake Pads]
[14235 Ignition Lead]
[11502 Wiper Blade]

To sort the collection based on on Part Id, change the compareTo method as below.

 public int compareTo( Part p){
      return this.number - p.number;
   }

Sorting collections using Comparator interface

Comparator is an interface similar to Comparable and can be used to sort the elements of a collection. It is part of the java.utils pacakage and has to be imported first. Here is an example which implements two sorting sequences using Comparator.

 // Import Comparator class
import java.util.Comparator;

Comparator nameSort = new Comparator() {
    @Override
   public int compare(Part o1, Part o2) {
      return o1.name.compareTo(o2.name);
   }
 };
 
 Comparator numberSort = new Comparator() {
   @Override
   public int compare(Part o1, Part o2) {
      return o1.number - o2.number;
   }
 };
// Call sort method with nameSort comparator
 Collections.sort(partsList, nameSort);
 
 // Call sort method with numberSort comparator
 Collections.sort(partsList, numberSort);

Difference between Comparable and Compares

The key differeces between comparator and comparable are:

Comparable is part of the java.lang package.

Comparator is part of the java.util package.

Comparable compares "this" object to the specified object.Comparator compares the two objects that are specified.

Comparable interface has compareTo(T o) method which takes one argument.

Comparator has compare(T o1, T o2) which takes two arguments.

The syntax for sort method when using Comparable is Collections.sort(List<T> list)

The syntax for sort method when using Comparator is Collections.sort(List<T> list, Comparator<? super T> c)

Use Comparable to implement default sorting.Use Comparator when you want to sort a collection in differnt ways.

Sorting a collection on multiple fields

You can use Comparable and Comparator interfaces to sort a collection on multiple fields. The example below shows sorting the Parts collection based name and number. In other words, the collection is sorted by Part name first, and if there are duplicate elements with the same name then they are sorted by Part number.

@Override
public int compareTo( Part p){
   int order = name.compareTo(p.name);
   if (order == 0) order = number - p.number;
 return order;
}

Using Comparator

Comparator nameNumberSort = new Comparator() {
   @Override
   public int compare(Part o1, Part o2) {
      int order = o1.name.compareTo(o2.name);
      if (order == 0 ) order = o1.number - o2.number;
      return order;
   }
};

Post a comment

Comments

Nothing yet..be the first to share wisdom.