Yesterday, I did a quick search for “Sort an array of objects with ColdFusion” and returned some pretty poor results so I wanted to take a moment to contribute an example to the community. This post shows how to quickly sort an array of objects into a struct and array.
/** I am an example object for a Blog Post. */
component
name = 'Character'
persistent = true
{
property
name="CharacterID"
fieldtype='id'
generator='native'
column='CHARACTER_ID';
/** Who is our Video Game Character? */
property
name='Name'
ormtype='string';
/** What video game does this character exist in? */
property
name='VideoGame'
ormtype='string'
column='VIDEO_GAME';
/** What is their score? This is just an example. */
property
name='Score'
ormtype='int';
/** 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;
};
}<cfscript>
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' }
];
</cfscript>Just some sample data so you don't have to have a database.
<cfscript>
// Populate some objects
objects = [];
n = arrayLen(examples);
for(i=1; i<=n; i++)
arrayAppend(objects, entityNew('Character').init(examples[i]) );
</cfscript>The above snippet is not rocket science. We’re passing a struct of example data into our object’s constructor to populate this instance.
<cfscript>
// 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}.{UUID} This is important otherwise any objects
// with the same value would be lost.
sort.sortedStruct.byScore[ objects[i].getScore() & '.' & createUUID() ] = objects[i];
sort.sortedStruct.byName[ objects[i].getName() & '.' & createUUID() ] = objects[i];
}
writeDump(var=sort.sortedStruct.byScore,label='Struct Sorted by Score');
writeDump(var=sort.sortedStruct.byName,label='Struct Sorted by Name');
</cfscript>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.
The hard work is already done by ColdFusion as structs are sorted by default:
At this point, we have a sorted struct in ascending order. You can use this struct with some of ColdFusion's struct methods (like structSort) to do what you need.
Step 2 (optional): Sorting Into Array
With just a little more work we can return an array sorted to our requirements.
<cfscript> // 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'); </cfscript>
<cfscript> // Similar work for sorting by score scores = structKeyArray(sort.sortedStruct.byScore); arraySort(scores, 'text', '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'); </cfscript>
Sorted arrays of objects! Notice the score was sorted as text. The value being sorted is {SCORE}.{UUID} which is a string.
Hope this helps you!
<cfscript>
// ------------------------------------------------------------------------------
// Prepare our 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' }
];
// Populate some objects
objects = [];
n = arrayLen(examples);
for(i=1; i<=n; i++)
arrayAppend(objects, entityNew('Character').init(examples[i]) );
// ------------------------------------------------------------------------------
// Now we have our example data, let's do some sorting!
// ------------------------------------------------------------------------------
// 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}.{UUID} This is important otherwise any objects
// with the same value would be lost.
sort.sortedStruct.byScore[ objects[i].getScore() & '.' & createUUID() ] = objects[i];
sort.sortedStruct.byName[ objects[i].getName() & '.' & createUUID() ] = objects[i];
}
writeDump(var=sort.sortedStruct.byScore,label='Struct Sorted by Score');
writeDump(var=sort.sortedStruct.byName,label='Struct Sorted by Name');
// ------------------------------------------------------------------------------
// You could be done. The structure created above is ready.
// But, if you need an array, a little more work is required.
// ------------------------------------------------------------------------------
// 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');
// Similar work for sorting by score
scores = structKeyArray(sort.sortedStruct.byScore);
arraySort(scores, 'text', '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');
</cfscript>
