Skip to main content
Ben Nadel at CFUNITED 2010 (Landsdown, VA) with: Jamie Samland
Ben Nadel at CFUNITED 2010 (Landsdown, VA) with: Jamie Samland

Exploring Array FoldLeft() Concepts In ColdFusion

By
Published in Comments (7)

As I've been making my way through the Seven Languages in Seven Weeks book by Bruce Tate, one of the language features that I find myself consistently enjoying is that of "fold left." Folding, in general, is the act of applying an operator and a running product to each value within an array in order to produce some final product that has been aggregated across the array. Fold "left" simply means that the we run from 1 to N. Fold "right," on the other hand, simply means that we run from N to 1. In my studies, it appears to be a super useful feature, so I wanted to try and implement it in ColdFusion.

Before we look at any code, it should be noted that I am running this demo in the context of my CFML preprocessor that makes inline function definition possible in ColdFusion. The preprocessor is using nothing more than variable substitution; as such, the same thing could be achieved with predefined functions.

That said, let's take a look at the function signature of arrayFoldLeft():

arrayFoldLeft( array, initialValue, operator ) :: product

The array parameter is the array over which we are applying the operator. The initialValue parameter is the "running product" that gets passed to the first array index (ie. the first execution of the operator). The operator parameter is a binary operator - a function that takes two arguments: the running product and the value located at the current array index:

operator( currentProduct, currentValue ) :: runningProduct

The operator will be applied at every index of the array and the return value of the operator execution will be passed-in as the "running product" to the next operator execution.

Ok, let's take a look at a demo of the arrayFoldLeft() function. And remember, this was run in the context of my CFML preprocessor:

<cffunction
	name="arrayFoldLeft"
	access="public"
	returntype="any"
	output="false"
	hint="I fold a product across the length of an array from 1 to N.">

	<!--- Define arguments. --->
	<cfargument
		name="array"
		type="array"
		required="true"
		hint="I am the array over which we are performing the foldLeft action."
		/>

	<cfargument
		name="initialProduct"
		type="any"
		required="false"
		hint="I am the initial value that gets passed as the product to the first array index."
		/>

	<cfargument
		name="operator"
		type="any"
		required="true"
		hint="I am the binary operator that will be applied to each array value. I take the current product and the current value."
		/>

	<!--- Define the local scope. --->
	<cfset var local = {} />

	<!---
		Start out with our product if the initial product is
		available. If not, then we'll just leave the local
		product undefined.
	--->
	<cfif !isNull( arguments.initialProduct )>

		<!--- Set the initial local product. --->
		<cfset local.product = arguments.initialProduct />

	</cfif>

	<!---
		Loop over each array index and apply the given operator
		to the value at the current index.
	--->
	<cfloop
		index="local.value"
		array="#arguments.array#">

		<!---
			Check to see if the product is currently available. If
			not, we need to explicitly pass NULL into the operator
			since we can't refer to a null value directly.
		--->
		<cfif isNull( local.product )>

			<!--- Padd in a null product. --->
			<cfset local.product = arguments.operator(
				javaCast( "null", "" ),
				local.value
				) />

		<cfelse>

			<!--- Pass in the current product. --->
			<cfset local.product = arguments.operator(
				local.product,
				local.value
				) />

		</cfif>

	</cfloop>

	<!---
		Return the aggregated product. Check to see if it is null.
		If it is, we need to return Void.
	--->
	<cfif isNull( local.product )>

		<!--- Return void. --->
		<cfreturn />

	<cfelse>

		<!--- Return the product. --->
		<cfreturn local.product />

	</cfif>
</cffunction>



<!--- ----------------------------------------------------- --->
<!--- ----------------------------------------------------- --->
<!--- ----------------------------------------------------- --->
<!--- ----------------------------------------------------- --->



<!--- Build up an array of numbers. --->
<cfset numbers = [ 1, 2, 3, 4, 5, 6, 7, 8, 9 ] />

<!---
	Now, get the multiplication product of all the numbers in the
	array (ie. what is the value of all the numbers in the array
	being multiplied together).
--->
<cfset product = arrayFoldLeft(
	numbers,
	1,
	<function( currentProduct, value ){
		<!--- Multiple the current product by the given value. --->
		<cfreturn( currentProduct * value ) />
	}>
	) />


<!--- Output the product. --->
<cfoutput>

	Product of Multiplication: #product#

</cfoutput>

In this demo, we are taking an array of numbers and figuring out what the product of all the numbers is. arrayFoldLeft() makes this concept quite simple; by folding the current product across the array, it makes it easy to multiply each number by the product of all the numbers before it. And, when we run the above code, we get the following output:

Product of Multiplication: 362880

When we call arrayFoldLeft(), we are passing in "1" as our initial value because anything times 1 is itself. Once we get past the first index, our running product then becomes the result of the previous operator.

This might seem like a lot of code because I had to define the actual arrayFoldLeft() method; but, if that was core to ColdFusion, running operations across an array would be as easy as: array, initial value, and operator! Of course, part of what makes this approach so appealing (to me) is the use of inline functions to make the entire operation all that much more succinct.

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

Reader Comments

15,902 Comments

@Lola,

In the homework, the most practical exercise that I saw was applying a collection of data to a given value. So, for example, let's say you have a block of text and you want to programmatically link given words in that block of text to a external pages (like linking dictionary words). You could fold the block of text across the collection of words, adding appropriate links as need-be.

Remember, the core functionality here is nothing new. We could do the same exact thing with a CFLoop/Array in which we manually kept a running product of the per-index operations. The only thing that foldLeft() adds for a CFLoop/Array is that it shoulders some of the lifting behind the scenes.

In the end, foldLeft() is just a convenience, not a really new type of functionality.

15,902 Comments

@Randall,

Like I told Sean in one of my posts, I am sure I would quickly abuse foldLeft(). I guess there's something about it that I just personally find very appealing. You can always loop over an array manually, but having the loop logic encapsulated just seems, juicy :)

167 Comments

I hope somebody will post more possible real-world uses for this as it does seem like it could be extremely handy -- but right now I can't see it.

15,902 Comments

@Randall,

Another use case for this might be to map one collection onto another. Most other languages have the concept of map() or filter() or things to that effect; but, the same could be accomplished with the foldLeft() approach:

<cfset numbers = [ 1, 2, 3, 4, 5 ] />
 
<cfset odds = foldLeft(
	numbers,
	[],
	<function( values, value ){
	<cfif (value mod 2)>
		<cfset arrayAppend( values, value ) />
	</cfif>
	<cfreturn values />
	}>
	) />

Here, we are mapping the numbers array onto an array that holds only the odd values. The "values" array is being built up over the collection of all numbers.

Might not be the best example, but you can start to see how this might be a very flexible function.

9 Comments

@ Lola

You probably know far more than me, but I too ask your type of questions. "How can I use this stuff? what for?"

I know nothing about Cold Fusion but have Version 9 on my Mac along w/ Dreamweaver found in CS 5. I've started with this link but it's over my head:

http://help.adobe.com/en_US/ColdFusion/9.0/CFMLRef/index.html

I know enough Dreamweaver (DW) to be dangerous. I started with Macromedia DW, then moved up to CS2, now to 5. I'm more of a philosopher / scientist and can only wish to be as smart as some of youz guyz on here when it comes to computer languages.

I'm fluent in 2 languages (human languages), can get by in about 3 others, but just stupid as heck when it comes to computer languages. HTML is a klunky for me. I want to become more fluid at computer codes. I own DW, and everything else contained in the Masters Collection of Adobe CS 5. I sure would like to be able to learn alot of it. Perhaps you can give me a hand. I'm disappointed in my website and know I can do so much more since I own the software.

Thanks!

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