How can I sort an array of objects with ColdFusion?
ColdFusion's struct data-type helps simplify sorting an array of objects (or other complex data-types). We will build a new struct where the key is the value we need to sort. We will also ensure that duplicate values are not lost in the process.
Setting up the Example: Example Object
Notice the init function shows two different methods of populating the object from a struct that contains a matching key for our properties. This is simply a bonus for this entry. Both methods work well.
/** I am an example object for a Blog Post. */
component
name = 'Character'
{
/** Who is our Video Game Character? */
property name='Name';
/** What video game does this character exist in? */
property
name='VideoGame';
/** What is their score? This is just an example. */
property
name='Score';
/** Construct */
public function init (struct memento)
{
// Here is a way to explicitly set properties
if (structKeyExists(arguments, 'memento')) {
setName(arguments.memento.name);
setVideoGame(arguments.memento.videoGame);
setScore(arguments.memento.score);
}
// This is a dynamic method. It does the same
// exact work as above but the code wont need
// to be maintained.
if (structKeyExists(arguments, 'memento'))
for (local.k in arguments.memento)
evaluate("set#local.k#(arguments.memento[local.k])");
return this;
};
}
Setting up the Example: Example Data
examples = [
// My Video Game Handle
{name = 'Aaron Greenlee (CrazedFan)',videoGame ='Call Of Duty 4', score = 19856 }
// One of my favorite games
,{name = 'Gordon Freeman', videoGame ='Half-Life Series', score = 1980 }
// COD/MW Rocks
,{name = 'John "Soap" MacTavish', videoGame ='Modern Warfare Series', score = 154 }
// Love to Mario!
,{name = 'Mario', videoGame ='Super Mario Bors.', score = 192553 }
// Back Back Forward
,{name = 'Raden', videoGame ='Mortal Kombat', score = 1545 }
// Valve Software is an amazing company. Mass respect.
,{name = 'GLaDOS', videoGame ='PORTAL', score = 0 }
// I never finish these games
,{name = 'Link', videoGame ='Zelda', score = '0' }
];
Setting up the Example: Populating Some Objects
The following code passes the struct with key that match the properties of our object. The object's init method will populate the object instance with the values from the struct.
// Populate some objects
objects = [];
n = arrayLen(examples);
for(i=1; i<=n; i++)
arrayAppend(objects, entityNew('Character').init(examples[i]) );
Step 1: Create and Sort a Struct
As we loop over the object I am concatenating the value to sort with a UUID to ensure each key is unique. Otherwise, objects with duplicate values are lost.
// Hold all our sorts
sort = {
sortedStruct = { byName = {}, byScore = {} }
,sortedArrays = { byName = [], byScore = [] }
};
// Sort into structs.
// We simply let CF do the hard work
n = arrayLen(objects);
for (i=1; i <= n; i++) {
// Each key in the struct is in the format of
// {VALUE}.{RAND NUMBER} This is important otherwise any objects
// with the same value would be lost.
rn = randRange(1,100);
sort.sortedStruct.byScore[ objects[i].getScore() & '.' & rn ] = objects[i];
sort.sortedStruct.byName[ objects[i].getName() & '.' & rn ] = objects[i];
}
// The hard work is already done by ColdFusion as structs are sorted by default!
writeDump(var=sort.sortedStruct.byScore,label='Struct Sorted by Score');
writeDump(var=sort.sortedStruct.byName,label='Struct Sorted by Name');
If you needed to sort your value in ascending order you can stop here. Your struct (in this case, sort.sortedStruct) has our objects sorted by Name and Score in ascending order.
Step 2: Sort into an Array.
Let's sort our objects within arrays. First, we will sort by name in ascending order:
// Sort the objects into an array by name.
names = structKeyArray(sort.sortedStruct.byName);
arraySort(names, 'text', 'asc');
n = arrayLen(names);
for (i=1; i <= n; i++)
arrayAppend(sort.sortedArrays.byName, sort.sortedStruct.byName[ names[i] ]);
writeDump(var=sort.sortedArrays.byName,label='Array Sorted by Name');
Pretty cool! But, we can also sort our array in descending order. To illustrate this, let's sort our objects by score in descending order.
// Similar work for sorting by score
scores = structKeyArray(sort.sortedStruct.byScore);
arraySort(scores, 'numeric', 'desc');
n = arrayLen(scores);
for (i=1; i <= n; i++)
arrayAppend(sort.sortedArrays.byScore, sort.sortedStruct.byScore[ scores[i] ]);
writeDump(var=sort.sortedArrays.byScore,label='Array Sorted by Score');
We now have a sorted array of objects! Please notice that the score was sorted as numeric.
+