CFML: Sorting an array of objects by a specific property
I've needed to do this a few times lately and keep forgetting how. Web searches don't immediately return anything CFML-specific, hence this quick reminder post.
The problem
Example scenario: you've created a simple array of blog Posts:
myPosts = [];
...and populated it with Post instances...
// 1
post1 = new Post();
post1.setTitle( "Post 1" );
post1.setDatePublication( ParseDateTime( "2018-02-01" ) );
myPosts.Append( post1 );
// 2
post2 = new Post();
post2.setTitle( "Post 2" );
post2.setDatePublication( ParseDateTime( "2018-01-01" ) );
myPosts.Append( post2 );
// 3
post3 = new Post();
post3.setTitle( "Post 3" );
post3.setDatePublication( ParseDateTime( "2018-03-01" ) );
myPosts.Append( post3 );
myPosts.each( function( post ){
echo( post.getTitle() & " published " & post.getDatePublication().DateFormat( "yyyy-mm-dd" ) & "<br>" );
});
/*
Post 1 published 2018-02-01
Post 2 published 2018-01-01
Post 3 published 2018-03-01
*/
...but you need the posts to be sorted by their publication date, rather than in the order the instances were appended to the array.
The solution
The answer is to sort the array using a closure which takes two elements of the array at a time and compares the two values of the property you specify.
myPosts.Sort( function( a, b ){
return Compare( a.getDatePublication(), b.getDatePublication() );
});
Which achieves the desired outcome:
myPosts.each( function( post ){
echo( post.getTitle() & " published " & post.getDatePublication().DateFormat( "yyyy-mm-dd" ) & "<br>" );
});
/*
Post 2 published 2018-01-01
Post 1 published 2018-02-01
Post 3 published 2018-03-01
*/
To reverse the order, i.e. sort the posts by date descending, you just swap over the values in the comparison test:
myPosts.sort( function( a, b ){
return Compare( b.getDatePublication(), a.getDatePublication() );
});
myPosts.each( function( post ){
echo( post.getTitle() & " published " & post.getDatePublication().DateFormat( "yyyy-mm-dd" ) & "<br>" );
});
/*
Post 3 published 2018-03-01
Post 1 published 2018-02-01
Post 2 published 2018-01-01
*/
Post-Script July 2020: Numeric values
I've realized that this solution doesn't apply when the property values you need to sort by are numbers.
This is because the Compare()
function will treat numeric values as strings, so that for example 11 will be sorted ahead of 2.
To sort numerically, we need to replace Compare()
with code that performs the same logic but on numbers:
myPosts.sort( function( a, b ){
if( a.postNumber() < b.postNumber() ) return -1;
if( a.postNumber() > b.postNumber() ) return 1;
return 0;
});
Comments