Sorting List of Objects in Apex and JS
As a Salesforce Developer, I've written numerous Apex Triggers, Apex Classes, and Lightning Web Components. Recently, I've found myself comparing Apex and JavaScript. I know they're quite different, with distinct use cases, but I've been thinking about how I can solve specific problems in each language. For example, How to manipulate collections, objects, and properties in both languages, as well as how to handle sorting. It's been an interesting exercise that helps me revise both languages in my head. Let's dive into discussing how to sort arrays in both Apex and JavaScript.
Let's begin with JavaScript, as it offers a straightforward way to sort arrays compared to Apex. Imagine we have an array of player objects, each containing properties like name and worldCup (representing their World Cup wins). Our goal is to sort this array based on the worldCup property of each player.
let players = [
{name: 'Leo Messi', worldCup: 1},
{name: 'Cristiano Ronaldo', worldCup: 0},
{name: 'Ronaldo Nazario', worldCup: 2}
];
//ascending order (for number value)
//array.sort(comparatorFunction)
players.sort((player1, player2) => player1.worldCup - player2.worldCup );
/*debug
asc by wc [{"name":"Cristiano Ronaldo","worldCup":0},{"name":"Leo Messi","worldCup":1},{"name":"Ronaldo Nazario","worldCup":2}]
*/
To sort an array in JavaScript, you can use the sort() method of the Array object (AKA Higher Order Function). This method takes a function as input. This input function compares pairs of elements in the array and tells sort() how to order them.
The input function needs to return a negative number if the first element should come before the second, a positive number if the first element should come after the second, and zero if they are equal. Based on these return values, sort() rearranges the array into the correct order.
Now, in Apex things are not as straightforward as JS. For Apex you have to use Comparator Interface. After the Salesforce new release, System.Comparator<sObject> Interface made the sorting of List with sObject easier than before. let's understand by example. First, we create the Apex class which implements System.Comparator<sObject>, which must implement the compare method and return an Integer. Source: Cool Stuff by Daniel Ballinger
Recommended by LinkedIn
public class sObjectComparator implements System.Comparator<sObject> {
// Asc and Desc are reserved keywords in Apex!
public enum SortOrder { Ascend, Descend}
private Schema.sObjectField sortField;
private DescribeFieldResult describeResult;
public SortOrder order {
get;
set {
order = value;
}
}
//constructor
public sObjectComparator(Schema.sObjectField compareField) {
sortField = compareField;
//get the field info
describeResult = sortField.getDescribe();
order = SortOrder.Ascend;
}
public integer compare(sObject s1, sObject s2) {
integer compareResult;
// Handle null objects before null field values
if(s1 == null && s2 == null) {
compareResult = 0;
} else if (s1 == null) {
compareResult = -1;
} else if (s2 == null) {
compareResult = 1;
} else {
object s1FieldValue = s1?.get(sortField);
object s2FieldValue = s2?.get(sortField);
// Handle null field values then actual value compares
if(s1FieldValue == null && s2FieldValue == null) {
compareResult = 0;
} else if (s1FieldValue == null) {
compareResult = -1;
} else if (s2FieldValue == null) {
compareResult = 1;
} else {
compareResult = compareFieldTypes(s1FieldValue, s2FieldValue);
}
}
if(order == SortOrder.Descend) {
return compareResult * -1;
}
return compareResult;
}
private integer compareFieldTypes(object s1FieldValue, object s2FieldValue) {
switch on (describeResult.getType()) {
when String {
string s1 = (string)s1FieldValue;
string s2 = (string)s2FieldValue;
return (s1 < s2) ? -1 : (s1 > s2) ? 1 : 0;
}
when DateTime {
DateTime s1 = (DateTime)s1FieldValue;
DateTime s2 = (DateTime)s2FieldValue;
return (s1 < s2) ? -1 : (s1 > s2) ? 1 : 0;
}
when Date {
Date s1 = (Date)s1FieldValue;
Date s2 = (Date)s2FieldValue;
return (s1 < s2) ? -1 : (s1 > s2) ? 1 : 0;
}
when Integer {
Integer s1 = (Integer)s1FieldValue;
Integer s2 = (Integer)s2FieldValue;
return (s1 < s2) ? -1 : (s1 > s2) ? 1 : 0;
}
when Double {
Double s1 = (Double)s1FieldValue;
Double s2 = (Double)s2FieldValue;
return (s1 < s2) ? -1 : (s1 > s2) ? 1 : 0;
}
when Id {
Id s1 = (Id)s1FieldValue;
Id s2 = (Id)s2FieldValue;
return (s1 < s2) ? -1 : (s1 > s2) ? 1 : 0;
}
when else {
Assert.fail('Unable to compare field type: ' + describeResult.getType());
}
}
return 0;
}
}
public Static void sortStudents(){
List<Student__c> studentList = new List<Student__c>();
studentList.add(new Student__c(Name='Ramos',Rank__c=6));
studentList.add(new Student__c(Name='Xavi',Rank__c=5));
studentList.add(new Student__c(Name='Busquets',Rank__c=3));
studentList.add(new Student__c(Name='Muller',Rank__c=4));
studentList.add(new Student__c(Name='Iniesta',Rank__c=1));
studentList.add(new Student__c(Name='Zidane',Rank__c=2));
sObjectComparator comp = new sObjectComparator(Student__c.Rank__c);
//pass the instance of sObjectComparator in sort method
studentList.sort(comp);
System.debug('Student__c list is '+studentList);
}
/*
debug
Student__c list is (Student__c:{Name=Iniesta, Rank__c=1}, Student__c:{Name=Zidane, Rank__c=2}, Student__c:{Name=Busquets, Rank__c=3}, Student__c:{Name=Muller, Rank__c=4}, Student__c:{Name=Xavi, Rank__c=5}, Student__c:{Name=Ramos, Rank__c=6})
*/
In the above example, after creating a bunch of Student__c records, create the instance of sObjectComparator (custom comparator class), specifying Student__c.Rank__c is the field to sort by. This instance is passed as a parameter to the sort method, which then sorts the list based on the specified field.
For example, I've only shown sorting in ascending order. However, you can modify the sObjectComparator class as you need, and can also make ASC/DESC as constructor parameters to control the order.
Thanks for your attention. I hope you have learned something new today.
What a way to teach something which is factual and inquisitive not only in terms of programming but in terms of football as well.