Menu

As simple as possible, as complex as necessary

CFML: Sorting an array of objects by a specific property

22 August 2018

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;
});

Posted on . Updated

Comments

  • Formatting comments: See this list of formatting tags you can use in your comments.
  • Want to paste code? Enclose within <pre><code> tags for syntax higlighting and better formatting and if possible use script. If your code includes "self-closing" tags, such as <cfargument>, you must add an explicit closing tag, otherwise it is likely to be mangled by the Disqus parser.
Back to the top