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 »
11,238 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 »
158 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 »
11,238 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 »
158 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 »
11,238 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
Ben Nadel's Company - Epicenter Consulting Recent Blog Comments
May 21, 2013 at 11:51 AM
Ask Ben: Parsing Very Large XML Documents In ColdFusion
Looking at my first ever XML document that I have to parse and put into MS SQL 2000 with CF8. I get it to list the desired Field name, many times over, and have a long list of this field name displa ... read »
May 21, 2013 at 9:25 AM
Turning Off and On Identity Column in SQL Server
you are awesome..i am lucky to get this blog between such a garbage one....Thanks, Prashant ... read »
May 20, 2013 at 4:38 PM
Using A Dynamic Column Name With ValueList() In ColdFusion
@Dana, Your confusion is well founded, since this is a very confusing features. In fact, it ONLY works if you use array notation. Meaning, that this: arrayToList( query[ "columnName" ] ) ... read »
May 20, 2013 at 4:34 PM
Using A Dynamic Column Name With ValueList() In ColdFusion
I was thinking chicken and the egg, I wouldn't have expected it to work in the valuelist going in I guess. Maybe I just need a beer, long day :) ... read »
May 20, 2013 at 4:29 PM
Using A Dynamic Column Name With ValueList() In ColdFusion
@Dana, That's if you're trying to reference a specific row. In this case, we're trying to reference the entire query column as one cohesive value. So, you are correct that if you wanted to output a ... read »
May 20, 2013 at 4:24 PM
Using A Dynamic Column Name With ValueList() In ColdFusion
I thought when you used array notation to reference queries you always had to have the row or it would throw a similar error as well? ... read »
May 20, 2013 at 11:45 AM
Using jQuery's Animate() Step Callback Function To Create Custom Animations
This is really useful. I found out that you don't actually have to use a dummy css property (surprisingly). To animate a property in a linear-gradient for instance I did this this.css('someLinearGra ... read »
May 20, 2013 at 10:51 AM
Using A Dynamic Column Name With ValueList() In ColdFusion
@Josh, Oh snap! You're totally right! I'm not sure I've ever tried that. I did know that you can call a number of other array-methods on ColdFusion query columns: http://www.bennadel.com/blog/167 ... read »
InVision App - Prototyping Made Beautiful With Prototyping Tools