This is a bit of a follow-up on my previous post Querying ColdFusion Data Structures where I explain how to use JXPath to query/filter ColdFusion structs. Querying is only ½ the picture though - we also need to be able to sort data.
Using arraySort is fine, if your array has nothing but strings or numbers, but it won't do for an array of structs, and is limited to sorting text and numbers, not complex objects.
Let us take for example an array of employee structs, something like this:
employees:[
{firstName:'John',lastName:'Doe'},
{firstName:'Ben',lastName:'Anderson'}
{firstName:'Jane',lastName:'Doe'},
]
We want to sort based on lastname and then firstname. In SQL this very simple:
SELECT * from EMPLOYEES ORDER BY lastName,firstNameWe could implement our own sort in ColdFusion, looping, and storing the sorted data in a new array, sure. But there's a way to do this using Java that requires a lot less code. We can leverage the java.util.Collections object, which has a sort() method that allows you to specify a java.util.List to sort, and a custom Comparator object.
import java.util.Comparator;
import java.util.Map;
public class EmployeeComparator implements Comparator {
public int compare(Object ob1, Object ob2) {
Map m1 = (Map)ob1;
Map m2 = (Map)ob2;
(String)m1LastName = (String)m1.get("LASTNAME");
(String)m2LastName = (String)m2.get("LASTNAME");
if (m1LastName.compareTo(m2LastName) == 0) {
String m1FirstName = (String)m1.get("FIRSTNAME");
String m2FirstName = (String)m2.get("FIRSTNAME");
return m1FirstName.compareTo(m2FirstName);
}
else {
return m1LastName.compareTo(m2LastName);
}
}
}
This works fine but there's a catch. We have to know our data structure format ahead of time, compile and deploy the class to the coldfusion server. It's not generic. We can implement a coldfusion.runtime.Struct specific comparator that will take a list of sort fields instead, which will take care of most of our needs with a single class. The only caveat is that those sort fields need to implement Comparable (which most of the basic types do).
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
import coldfusion.runtime.Struct;
public class StructComparator implements Comparator<Struct> {
private final List<String> sortFields;
public StructComparator(String fields) {
sortFields = Arrays.asList(fields.split(","));
}
@SuppressWarnings({ "rawtypes", "unchecked" })
public int compare(Struct struct1, Struct struct2) {
for (String field : sortFields) {
Comparable x = (Comparable)struct1.get(field);
Comparable y = (Comparable)struct2.get(field);
if (x.compareTo(y) != 0) {
return x.compareTo(y);
}
}
return 0;
}
}
This sorts all the fields passed in, in order, in the same direction. And since we're using Struct.get() to pull values, we don't have to worry about case sensitivity either. I'll leave it as an exercise to the reader to enhance this class to allow specifying the sort direction and other options. Happy coding!


