Aaron Greenlee.com | A Personal Journey.
You should follow me here.
This is the RSS subscription you have been looking for.
 
Wrecking Ball Media
A great team that is clearing the way for digital marketing.

Have you thought about joining the Central Florida Web Developers User Group?

Sort Array of Objects in ColdFusion

POSTED Thursday, September 30, 2010  |   | DOWNLOAD CODE
Keywords: Objects, ColdFusion

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.

Setting up the Example: Example Object
/** 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;
	};

}
Setting up the Example: Example Data
<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.

Setting up the Example: Populating Our Objects
<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.

Step 1: Sorting Into Struct
<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.

An Array of Objects Sorted by Name
<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>
An Array of Objects Sorted by Score
<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!

The Entire Process in One Snippet
<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>
blog comments powered by Disqus
You can send me email or work with
   me for digital marketing, web design
      and application development.

         I own proprietary web application development
         company and work with a leading digital marketing firm.
© 2009 - 2014 Aaron Greenlee. Powered by my own code on the ColdBox Framework.

This site is best viewed on Chrome, FireFox and Safari. Subscribe to my RSS feed.