Code Kata: Compacting Arrays In ColdFusion
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:
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
I always enjoy your code kata's. Good stuff! That's all I have to say about that. 🙏
@Chris,
Thank you, good sir. It's always fun to take the brain on these little tangents.
Post A Comment — ❤️ I'd Love To Hear From You! ❤️
Post a Comment →