Archive for February, 2008

Merge Sort an Array of Structures in ColdFusion

After a recent spell of doing lots of prototyping, I’m finally getting back to some proper coding. I have an array of structures that I’d been sorting on a particular key (price) using a quick bubble sort algorithm. However, with real data on the site it was randomly returning errors and proving fairly unstable.

I knew there were better algorithms out there, so I thought I’d try a Merge Sort, and wrote a version in cfscript… posted here for your pleasure :-)

<cfscript>
	/**
	 * Sorts an array of structures using the Merge Sort algorithm.
	 *
	 * @param arr 	 The array to sort. (Required)
	 * @param key 	 Structure Key to sort by (Required)
	 * @return Returns an array.
	 * @author Anthony Cooper (ant@outsrc.co.uk)
	 * @version 1, 8 Feb 2008
	 */

	function MergeSort( arr, key ) {
	    var leftArray = ArrayNew( 1 );
	    var rightArray = ArrayNew( 1 );
	    var result = ArrayNew( 1 );
	    var middle = 0;
	    var i = 0;

	    if ( ArrayLen( arr ) LTE 1 ) {
	    	return arr;
	    }
	    else {
			middle = Ceiling( ArrayLen( arr ) / 2 );
			for ( i = 1; i LTE middle; i++ ) {
				ArrayAppend( leftArray, arr[ i ] );
			}
			for ( i = ( middle + 1 ); i LTE ArrayLen( arr ); i++ ) {
				ArrayAppend( rightArray, arr[ i ] );
			}
			leftArray = MergeSort( leftArray, key );
			rightArray = MergeSort( rightArray, key );
			result = Merge( leftArray, rightArray, key );

			return result;
	    }
	}

	function Merge( leftArray, rightArray, key ) {
		var result = ArrayNew( 1 );

		while ( ArrayLen( leftArray ) > 0 AND ArrayLen( rightArray ) > 0 ) {
			if ( leftArray[ 1 ][ key ] <= rightArray[ 1 ][ key ] ) {
				ArrayAppend( result, leftArray[ 1 ] );
				ArrayDeleteAt( leftArray, 1 );
			}
			else {
				ArrayAppend( result, rightArray[ 1 ] );
				ArrayDeleteAt( rightArray, 1 );
			}
		}
		if ( ArrayLen( leftArray ) > 0 ) {
			result = ArrayJoin( result, leftArray );
		}
		if ( ArrayLen( rightArray ) > 0 ) {
			result = ArrayJoin( result, rightArray );
		}

		return result;
	}

	function ArrayJoin( firstArray, secondArray ) {
		var i = 0;
		for ( i = 1; i <= ArrayLen( secondArray ); i++ ) {
			ArrayAppend( firstArray, secondArray[ i ] );
		}
		return firstArray;
	}
</cfscript>

And here’s how you’d use it…

<cfscript>
	products = ArrayNew( 1 );

	products[1] = { name = "Jacket", price = "2999" };
	products[2] = { name = "Shoes", price = "2199" };
	products[3] = { name = "Slacks", price = "1999" };

	sortedProducts = MergeSort( products, "price" );
</cfscript>

Disclaimer: I’m not claiming this is perfect, and I know it could be improved upon and sort direction etc added. But it was a quick solution to my problem. I’d be interested in others feedback.