May 23, 2012

Apex Summer’12 Comparable interface Sorting Examples : Part 1

I am happy about the native sorting support in Apex for UDT(User Defined Types), I was missing this a lot since I am java developer who is used to of Comparable and Comparator based sorting.

Another reason of drafting this post, is because I didn’t liked the sorting example available in apex developer guide, this example is complex way to achieve the desired.

Sample APEX Class

Following apex class with following 4 different type of attributes is used for illustration

  • Name : Type = String
  • Age : Type = Integer
  • DOJ : Type = Date
  • checkInTime : Type = Datetime

global class Employee implements Comparable {
 public String name;
 public Integer age;
 public Date doj;
 public Datetime checkInTime;
 
 public Employee (String n, Integer a, Date d, DateTime c) {
  this.name = n;
  this.age = a;
  this.doj = d; 
  this.checkInTime = c;
 } 
 global Integer compareTo(Object other) {
   // will be shown in code snippets below
 }
}

 

Sample Test Fixture

Once the comparable contract i.e. compateTo() method is added, you can test the functionality by executing the code below in anonymous block

Employee [] employees = new Employee[] {
          new Employee('Abhinav', 30, Date.newInstance(2011, 06, 16), System.now().addHours(1)),
          new Employee('Vijay', 20, Date.newInstance(2010, 01, 11), System.now().addHours(2)),
          new Employee('John', 50, Date.newInstance(2007, 01, 1), System.now().addHours(3)), 
          new Employee('Bill', 40, Date.newInstance(2000, 04, 3), System.now().addHours(4))            
           };
// this will sort on the basis of Comparable
employees.sort();
// print to see the results
System.debug(employees);

 

Sorting by Age (Integer)

Sorting on number attributes is simplest, you can just subtract the numbers to return the negative, zero or positive value. Here is how Employee class will be naturally sortable on age

    // sort on age
    global Integer compareTo(Object other) {
        Integer otherAge = other != null ? ((Employee)other).age : 0;            
        // subtraction between this and other age will do the required
        return this.age - otherAge;
    } 
   

on executing the above test fixture this prints

Employee:[age=20, checkInTime=2012-05-23 14:26:22, doj=2010-01-11 00:00:00, name=Vijay], 
Employee:[age=30, checkInTime=2012-05-23 13:26:22, doj=2011-06-16 00:00:00, name=Abhinav], 
Employee:[age=40, checkInTime=2012-05-23 16:26:22, doj=2000-04-03 00:00:00, name=Bill]
Employee:[age=50, checkInTime=2012-05-23 15:26:22, doj=2007-01-01 00:00:00, name=John], 

 

Sorting by Name (String)

Sorting strings is simple because of presence of String.compareTo(String) method. What this means is String implements Comparable as well, so we can use call the same method to do the heavy lifting. Here is the Employee class sortable on name attribute

// sort on name
  global Integer compareTo(Object other) {
    String otherName = other != null ? ((Employee)other).name : '';            
    // use string class compareTo()
    return this.name.compareTo(otherName);
  }

Here are the results

Employee:[age=30, checkInTime=2012-05-23 13:33:39, doj=2011-06-16 00:00:00, name=Abhinav], 
Employee:[age=40, checkInTime=2012-05-23 16:33:39, doj=2000-04-03 00:00:00, name=Bill], 
Employee:[age=50, checkInTime=2012-05-23 15:33:39, doj=2007-01-01 00:00:00, name=John], 
Employee:[age=20, checkInTime=2012-05-23 14:33:39, doj=2010-01-11 00:00:00, name=Vijay]

Sorting on DOJ (Date)

With dates we can use the daysBetween() method to do the heavy lifting, as indicated below:

// sort on date
global Integer compareTo(Object other) {
    // assuming if their is no date, it would be TODAY
    // this might not be applicable for your biz logic
    // so please take care of that
    Date otherDOJ = other != null ? ((Employee)other).doj : System.today();            
    return otherDOJ.daysBetween(this.doj);
}

here are the results

Employee:[age=40, checkInTime=2012-05-23 16:26:22, doj=2000-04-03 00:00:00, name=Bill],
Employee:[age=50, checkInTime=2012-05-23 15:26:22, doj=2007-01-01 00:00:00, name=John], 
Employee:[age=20, checkInTime=2012-05-23 14:26:22, doj=2010-01-11 00:00:00, name=Vijay], 
Employee:[age=30, checkInTime=2012-05-23 13:26:22, doj=2011-06-16 00:00:00, name=Abhinav], 

 

Sorting on checkInTime(DateTime)

Again with Datetime, we can use time past in millis to make the sorting easy. Here is the sample

global Integer compareTo(Object other) {
    // assuming if their is no datetime, it would be NOW
    // this might not be applicable for your biz logic
    // so please take care of that
    DateTime otherCheckInTime = other != null ? ((Employee)other).checkInTime : System.now();            
    // use Datetime.getTime() to do get the numeric time in millis
    return (this.checkInTime.getTime() - otherCheckInTime.getTime()).intValue();
}

here are the results

Employee:[age=30, checkInTime=2012-05-23 13:26:22, doj=2011-06-16 00:00:00, name=Abhinav], 
Employee:[age=20, checkInTime=2012-05-23 14:26:22, doj=2010-01-11 00:00:00, name=Vijay], 
Employee:[age=50, checkInTime=2012-05-23 15:26:22, doj=2007-01-01 00:00:00, name=John], 
Employee:[age=40, checkInTime=2012-05-23 16:26:22, doj=2000-04-03 00:00:00, name=Bill])

 

Sorting in DESCENDING order

All the above sort samples, do the sorting in ASCENDING order. Reversing the order is very easy, one can just swap the this and other attributes in compareTo() method, here are the swapped line samples

//Name
return otherName.compareTo(this.name);
// CheckinTime
return (otherCheckInTime.getTime() - this.checkInTime.getTime()).intValue();
//DOJ
return this.doj.daysBetween(otherDOJ);
//Age
return otherAge - this.age;

 

Related reading

Your thoughts

Looking forward for the same !