Skip to main content
Ben Nadel at cf.Objective() 2013 (Bloomington, MN) with: Erik Meier
Ben Nadel at cf.Objective() 2013 (Bloomington, MN) with: Erik Meier

Normalizing Collection Entries In ColdFusion

By
Published in Comments (3)

In Lucee CFML, looping over collections is effortless because Lucee exposes both the key and value attributes on the CFLoop tag. Furthermore, you can even use struct instead of collection for a more intuitive read on the code. Unfortunately, Adobe ColdFusion hasn't caught up with these ergonomics niceties just yet. As such, I created a user defined function (UDF) that normalizes collections (Structs and Arrays) into an array that always exposes index, key, and value.

The toEntries() UDF is straightforward—it takes a collection and then uses .map() to return a new array that has a more comprehensive set of properties:

<cfscript>

	/**
	* I return the entries for the given collection (Array or Struct). Each entry is a
	* struct with a normalized set of keys: index, key, value.
	*/
	public array function toEntries( required any collection ) {

		if ( isArray( collection ) ) {

			return collection.map(
				( value, i ) => {

					return {
						index: i,
						key: i,
						value: value
					};

				}
			);

		}

		if ( isStruct( collection ) ) {

			return collection.keyArray().map(
				( key, i ) => {

					return {
						index: i,
						key: key,
						value: collection[ key ]
					};

				}
			);

		}

		throw(
			type = "UnsupportedCollectionType",
			message = "Entries cannot be taken from unsupported collection type."
		);

	}

</cfscript>

When dealing with an array, it's a little quirky that the index and key values are both the iteration offset. But, this keeps it consistent with the struct iteration, which does differentiate between the struct key and the iteration offset.

To see this in action, let's dump-out the entries for both a struct and an array:

<cfscript>

	include "./utils.cfm";

	writeDump(
		label = "From Struct",
		var = toEntries({
			"foo": "bar",
			"hello": "world",
			"fizz": "buzz"
		})
	);

	writeDump(
		label = "From Array",
		var = toEntries([
			"Just",
			"Do",
			"It"
		])
	);

</cfscript>

When we run this ColdFusion code, we get the following page output:

Two sets of entries, one from a struct, one from an array in ColdFusion.

As you can see, the toEntries() function exposed the same set of keys when consuming either the struct or the array.

To be clear, this isn't a function that I would use all the time. It might not even be a function that I use very often. But, it can be helpful when generating HTML output. This is especially true when linking off to other pages from a complex data structure&madsh;having the index, the key, and the value can making formatting the HTML and generating href attributes easier.

For example, having the index makes zebra-stripping easier. In the following ColdFusion code, each iteration receives an optional CSS class based on its iteration offset.

<cfscript>

	include "./utils.cfm";

	data = {
		"foo": "bar",
		"hello": "world",
		"fizz": "buzz",
		"spicy": "meatball"
	};

</cfscript>
<cfoutput>

	<style type="text/css">
		.odd {
			background-color: ##f0f0f0 ;
		}
	</style>

	<cfloop index="entry" array="#toEntries( data )#">

		<p class="<cfif ( entry.index % 2 )>odd</cfif>">
			#encodeForHtml( entry.key )#
			&rarr;
			#encodeForHtml( entry.value )#
		</p>

	</cfloop>

</cfoutput>

Here, we're using the modulo operator to apply the odd CSS class to odd rows in the output. And, when we run this ColdFusion code, we get the following output:

HTML with zebra-stripe formatting produced from ColdFusion.

One day, I hope that Adobe ColdFusion updates their CFLoop tag and makes this toEntries() function superfluous. But, for the time being, this function makes my life easier.

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