Skip to main content
Ben Nadel at cf.Objective() 2014 (Bloomington, MN) with: Matthew Reinbold
Ben Nadel at cf.Objective() 2014 (Bloomington, MN) with: Matthew Reinbold ( @libel_vox )

Code Kata: Compacting Arrays In ColdFusion

By on
Tags:

On the way home from CFCamp 2023, I was listening to a Remote Ruby podcast episode in which the hosts talked about "compacting" arrays. Compacting means to remove the null / undefined indices from the array in order to make consuming the resultant array more predictable (no worry of null-reference errors, "NRE"). Having been away from desk most of the week, I'm super itchy to write some CFML. As such, I thought it would be a fun code kata to write an array compacting function in ColdFusion.

When it comes to the CFML engines, there are different behaviors that we must take into account when writing a compatible arrayCompact() function. In Adobe ColdFusion, null indices are implicitly skipped when using for-of iteration; and, in Lucee CFML, null indices are implicitly skipped when using methods like .filter() and .each(). For my approach, I'm using the .filter() method and then applying some additional logic for Adobe ColdFusion.

If I was going to write the arrayCompact() function for Lucee CFML only, it would be as simple as calling the .filter() method and filtering-in all values:

values.filter( ( value ) => true )

Since Lucee CFML implicitly skips null / undefined indices in .filter(), we know that only defined values will get included in our filter operation. Compacting achieved!

But, since we want this to work with Adobe ColdFusion as well, we have to go the extra step with our .filter() call and make sure that the value argument is non-Null:

values.filter( ( value ) => ! isNull( value ) )

Let's see this in action:

<cfscript>

	// Defines functions like dump(), echo(), and nullValue() in Adobe ColdFusion context.
	include "./fn-compat.cfm";

	// ------------------------------------------------------------------------------- //
	// ------------------------------------------------------------------------------- //

	// Mixed array with defined + undefined values.
	mixedValues = [ nullValue(), "b", "c", nullValue(), "e", "f", nullValue() ];

	// Here, we're filtering-in ALL VALUES in order to demonstrate the differences between
	// the two CFML engines.
	filteredValues = mixedValues.filter(
		( value ) => {

			return( true );

		}
	);

	dump( "#server.coldfusion.productName# : #server.coldfusion.productVersion#" );
	dump(
		label = "Filtered-In Values",
		var = filteredValues
	);
	dump(
		label = "Compacted Values",
		var = arrayCompact( mixedValues )
	);

	// ------------------------------------------------------------------------------- //
	// ------------------------------------------------------------------------------- //

	/**
	* I return the given value with undefined indices removed.
	*/
	public array function arrayCompact( required array input ) {

		// Adobe ColdFusion and Lucee CFML handle filtering differently. In Lucee CFML,
		// the .filter() method inherently skips over undefined indices. As such, in order
		// to compact an array in Lucee, all we would have to do is _filter_ all values
		// into the resultant array:
		// 
		// return( input.filter( ( value ) => true ) );
		// 
		// However, Adobe ColdFusion will pass undefined indices to the .filter() method.
		// As such, in order to get this to work in both Adobe ColdFusion and Lucee CFML,
		// we have to check for non-null values in the filter:
		return(
			input.filter(
				( value ) => {

					return( ! isNull( value ) );

				}
			)
		);

	}

</cfscript>

As you can see, we're constructing an array of mixed defined / undefined values. Then, we try to filter-in all values (in order to see the difference between the CFML engines); and, compare that to our arrayCompact() method. When we run this in both Lucee CFML and Adobe ColdFusion, we get the following output:

An array being compacted in both Lucee CFML and Adobe ColdFusion.

As you can see from the first dump() call, simply calling .filter() is sufficient in Lucee CFML. It's only because Adobe ColdFusion includes the undefined values that we need to take the algorithm one step further and actually inspect the operator / iterator value. Ultimately, the second dump() call demonstrates that the array has been successfully compacted in both CFML engines.

Want to use code from this post? Check out the license.

Reader Comments

Post A Comment — I'd Love To Hear From You!

Post a Comment

I believe in love. I believe in compassion. I believe in human rights. I believe that we can afford to give more of these gifts to the world around us because it costs us nothing to be decent and kind and understanding. And, I want you to know that when you land on this site, you are accepted for who you are, no matter how you identify, what truths you live, or whatever kind of goofy shit makes you feel alive! Rock on with your bad self!
Ben Nadel