Developer

Use arrays and structures in ColdFusion

Complex variables help you get more out of ColdFusion, and they're easier to use than you might think. Brian Kotek explains how arrays and structures put problem-solving power in your development toolbox.


ColdFusion Markup Language (CFML) lets you create variables to store data. Variables in CFML fall into two categories: simple and complex. Simple variables are things like string values, numeric values, lists, and dates. Complex variables are arrays, structures, and recordsets. Most ColdFusion developers can create recordsets easily enough—simply query a database and get back a recordset. However, arrays and structures are a bit more challenging for new developers to get their heads around.

Using these so-called complex variables is actually quite easy, and the payoff is a big one: Arrays and structures put a lot of problem-solving power in your development toolkit.

Structures
Structures are great because they let you associate properties with a conceptual object in your application. For example, in the course of building an online store, it’s useful to have the idea of a “customer.” My customers can create profiles, and when they return to my store, the application uses their profile data. Customer profile data might contain the customer’s first name, last name, e-mail address, and postal code. A structure enables me to keep all this data together in one variable. For example, I’ll create a new structure called “customer”:
<cfset customer = structnew()>

Next, I’ll associate my customer properties with the customer using a dot-separated syntax, like this:
<cfset customer.firstname = “Ned”>
<cfset customer.lastname = “Peterson”>
<cfset customer.emailaddress = ned@xzy.com>
<cfset customer.zipcode = “12345”>

Now, anywhere in my code that I want to access a customer property, I can do it simply by referencing the appropriate key in my customer structure. This is why structures are sometimes called key-value pairs or associative arrays. If I want the customer’s postal code, I just use:
<cfoutput>
Your zip code is #customer.zipcode#.
</cfoutput>

There are several CFML functions specifically meant to be used with structures:
  • Structkeylist() returns a list of the keys that a structure has. So our structkeylist() would return “firstname,lastname,emailaddress,zipcode.”
  • Structsort() lets you order the items in your structure.
  • Structclear() empties out the structure and deletes all the keys.
  • IsStruct() returns true if the variable in question is indeed a structure.
  • StructFind() lets you search the structure to find a specific value.

There are more, but I think you see the point. Structures are easy to use and very handy for grouping related data into a single variable.

Arrays
Arrays are kind of like the big brother of structures. One main difference is that structures use a dot-delimited syntax, such as “customer.firstname,” whereas arrays are referenced by numeric value. Another key difference is that arrays are multidimensional, meaning that they can hold multiple sets of information.

I often find it helpful to visualize arrays as tables similar to an Excel spreadsheet. Table A shows an array with only one dimension.
Table A
my1DArray:
my1DArray[1]
my1DArray[2]
my1DArray[3]
my1DArray[4]
One-dimensional array

You can see that Table A is basically a single “column” of data. The table shows how you would reference each “cell” in the array. We call each item in the array an element. It’s important to note that the first element in an array always starts with the numeral one. Most other languages start with zero. I personally think it’s much more intuitive to start with one instead of zero, but others would disagree.

I can create a one-dimensional array called “my1DArray” and populate it like this:
<cfscript>
my1DArray = arrayNew(1);
my1DArray[1] = 'Dave';
my1DArray[2] = 'Jennifer';
my1DArray[3] = 'Heather';
my1DArray[4] = 'Karl';
 </cfscript>


I can reference the third element in this array with this snippet:
The third item in the array is: #my1DArray[3]#

This would output:
The third item in the array is: Heather

There are a number of CFML functions specifically designed for arrays, including arrayMax(), which returns the largest value in the array; arraySort(), which sorts the array; arrayDeleteAt(), which deletes the element you specify; and arrayLen(), which returns the number of elements in the specified array. An example of using an array function is:
There are #arrayLen( my1DArray )# items in the array.

This would output:
There are 4 items in the array.

If I wanted to output each element in the array, this would do it:
<cfloop index="thisElement" from="1" to="#arraylen( my1DArray )#">
#my1Darray[thisElement]#<br>
</cfloop>

The output would be:
Dave
Jennifer
Heather
Karl


Notice that this one-dimensional array is similar to the structure I created earlier, except the elements are referenced by number instead of key. However, with arrays, we can go to two dimensions and higher. Table B shows a two-dimensional (2D) array.
Table B
my2DArray:
my2DArray[1][1] my2DArray[1][2] my2DArray[1][3]
my2DArray[2][1] my2DArray[2][2]  
my2DArray[3][1] my2DArray[3][2] my2DArray[3][3]
Two-dimensional array

Now this is starting to look more like an Excel spreadsheet. I could create a 2D array with this code:
<cfscript>
my2DArray = arrayNew(2);
my2DArray[1][1] = 'First Row First Column';
my2DArray[1][2] = 'First Row Second Column';
my2DArray[1][3] = 'First Row Third Column';
my2DArray[2][1] = 'Second Row First Column';
my2DArray[2][2] = 'Second Row Second Column';
my2DArray[3][1] = 'Third Row First Column';
my2DArray[3][2] = 'Third Row Second Column';
my2DArray[3][3] = 'Third Row Third Column';
</cfscript>


See why it’s a 2D array? Each element is referenced by two numbers—a “row” number and a “column” number. All the array functions work on 2D arrays too. You just need to be a bit more specific in how you reference the elements:
The second row in the array has #arrayLen( my2DArray[2] )# columns in it.<br>
But the third row in the array has #arrayLen( my2DArray[3] )# columns in it

Would output:
The second row in the array has 2 columns in it.
But the third row in the array has 3 columns in it

Looping over a 2D array requires that you use nested loops to output each element, one that loops over each “row,” and a second loop that steps through each “column” in the “row”:
<cfloop index="thisRow" from="1" to="#arraylen( my2DArray )#">
<cfloop index="thisColumn" from="1" to="#arraylen( my2DArray[thisRow] )#">
#my2Darray[thisRow][thisColumn]#<br>
</cfloop>
————-<br>
</cfloop>


This would output:
First Row First Column
First Row Second Column
First Row Third Column
————-
Second Row First Column
Second Row Second Column
————-
Third Row First Column
Third Row Second Column
Third Row Third Column
————-


You can create three-dimensional (3D) arrays, which basically act like a “Rubik’s Cube” of data, but I’ve found few instances where a 3D array is necessary.

Which should you use?
Structures and arrays each have advantages and drawbacks. I can only speak from personal experience, but if I have a variable that has a predefined number of elements associated with it, such as a customer, I’ll most often use a structure. To me, it’s a lot easer to remember “customer.lastname” than “customer[2].” However, if I’m creating a variable that has an arbitrary number of elements associated with it, such as a shopping cart, I’ll use arrays.

Editor's Picks