Exploring Array FoldLeft() Concepts In ColdFusion

Posted December 29, 2010 at 9:06 AM by Ben Nadel

Tags: ColdFusion

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.


You Might Also Be Interested In:



Reader Comments

Dec 29, 2010 at 9:40 AM // reply »
148 Comments

What would the practical use of this be?


Dec 29, 2010 at 9:47 AM // reply »
10,743 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.


Dec 29, 2010 at 10:34 AM // reply »
154 Comments

@Ben,

I was going to ask the same thing, but I suppose this could come in handy someday.

Lola, also see: http://www.bennadel.com/blog/2078-Seven-Languages-In-Seven-Weeks-Scala-Day-2.htm

And as you said "the quick brown fox" could be turned in to

  • "href="dict.com?the">the</><href="dict.com?quick">quick</>..."

Seems almost like "foldLeft" should be renamed "replaceWith."


Dec 29, 2010 at 10:41 AM // reply »
10,743 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 :)


Dec 29, 2010 at 10:58 AM // reply »
154 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.


Dec 29, 2010 at 11:06 AM // reply »
10,743 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.


Jan 2, 2011 at 12:50 AM // reply »
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!


Post A Comment

Comment Etiquette: Please do not post spam. Please keep the comments on-topic. Please do not post unrelated questions or large chunks of code. And, above all, please be nice to each other - we're trying to have a good conversation here.

Please review the following issues:

Author Name:


Author Email:

Author Website:

Comment:

Supported HTML tags for formatting: <strong>bold</strong>   <em>italic</em>   <code>code</code>







  • Help Wanted - Find Your Next ColdFusion Job
InVision App - Prototyping Made Beautiful With Prototyping Tools Ben Nadel's Company - Epicenter Consulting Recent Blog Comments
May 16, 2012 at 8:18 PM
Best Of ColdFusion 10 Contest Entry - HTML Email Utility
Just found this, looks good! I'm trying to run it on local, it's the 64bit version and I'm experiencing horrible lag. On average the generate.cfm processes the content change in 60-90 seconds. I've ... read »
May 16, 2012 at 6:40 PM
Maintaining Sessions Across Multiple ColdFusion CFHttp Requests
I am trying to integrate this CFHTTPsession into an application that will log into zeekrewards.com to post ads and I am not having any luck. The code works perfectly for logging into other websites, ... read »
May 16, 2012 at 2:44 PM
Creating A Sometimes-Fixed-Position Element With jQuery
Thank you, very useful technique! Worked like a charm. ... read »
May 16, 2012 at 1:58 PM
Movies As A Religious Experience
Acting can, in a way, ruin the movie-goer's experience. I used to be able to get so caught up in movies and their plots, and totally engaged. But lately, I haven't been able to as much with a lot o ... read »
May 16, 2012 at 1:52 PM
The Science Of Optimal Post-Exercise Nutrition
children of this age eat very less vegetables so u can opt for salads they will like it also carrot ,cucumber,onion and as far as pulses are concerned u can boil them ,give him along with mashed rice ... read »
May 16, 2012 at 1:34 PM
Strange ColdFusion JRUN Stack Overflow Error
Hey, Recently I updated my jrun4 using the latest updater 7 and now i am having memory issues :(:(:( any help is appreciated ... read »
May 16, 2012 at 9:56 AM
ColdFusion 10 Beta, Apache Tomcat, And Symbolic Links On Mac OSX
Hi, Now that ColdFusion 10 is out I have stumbled over this as well and I cannot figure out the proper solution. We're running virtual hosts via Apache2; the ColdFusion-applications store their fil ... read »
May 15, 2012 at 6:03 PM
Movies As A Religious Experience
@Ben, I don't know whether you'd consider this a religious observation, but it seems to me, in a sense, movies multiply how many lives we get to have. Each movie is like a little extra life we get ... read »