Understanding Arrays and Structures
in ColdFusion
Part 1 of an Ongoing Saga:
Arrays
An array is known as a complex datatype in ColdFusion. Don?t let the term fool
you. Complex doesn?t mean they?re hard to understand. Complex only means that
they are multidimensional.
What is a multidimensional variable, and why would you want to burden yourself
with it? Allow me to explain.
First, let?s take a look at a ?simple? variable?one that you?re more than likely
intimately familiar with.
<cfset player = ?John?
/>
Let?s say John is a player on a baseball team (no, I don?t know which team
specifically?pick your favorite and play along).
That was easy enough. We?ve now got a local variable named ?player? with a value
of ?John?.
What if we want to store the names of the other eight players on the team?
Sure, we can do:
<cfset player1 = ?John?
/>
<cfset player2 = ?Bob?
/>
<cfset player3 = ?Frank?
/>
<cfset player4 = ?Pete?
/>
<cfset player5 = ?Hank?
/>
<cfset player6 = ?Dave?
/>
<cfset player7 = ?Craig?
/>
<cfset player8 = ?Bill?
/>
<cfset player9 = ?Curly Joe?
/>
...but now we have to worry about maintaining 9 separate variables. If we want
to pass the names of the players on the team to another page, we have to
manually pass 9 variables (be it in a URL, form fields, sessions, etc). That
leaves a lot of room for error.
Not only that?but what if there were more than 9 ?items? that we were concerned
with? What if we were tracking the 30 people working in a particular department?
Or the 100 items in inventory? Or the 1700 ways that ColdFusion is better than
ASP? (ahem?I digress?).
Back to the 9 players. Now, it is possible to do something like:
<cfset players = ?John, Bob,
Frank, Pete, Hank, Dave, Craig, Bill, Curly Joe? />
...which will effectively store the 9 values in one variable. ColdFusion even
provides various list functions that will help manipulate/extract values from
the list variable. However, list manipulation in CF is relatively slow
(especially when compared to array manipulation). Especially if the length of
the list begins to approach 1700 items!
So how to efficiently manage multiple values such as this? The answer is?of
course? (everybody say it together)?. the array.
1 Dimensional Arrays
As I?ve already mentioned, arrays are multidimensional?and we?ll soon discuss
that. But arrays can also be 1 dimensional. Let?s take a look at that first.
<cfset arrPlayers = arrayNew(1) />
An array is created with ColdFusion?s arrayNew() function. arrayNew() takes one
argument?the dimensions of the array. ColdFusion supports up to a 3 dimensional
array. For this example, we?re creating a simple 1 dimensional array. It is not
necessary to preface the name of the variable with ?arr?. This is simply a
convention that many people use in order to distinguish between various variable
types. You can name your array any syntactically valid ColdFusion variable name
(e.g. cannot begin with a number, cannot contain special characters or spaces).
To populate the array once it?s been created:
<cfset arrPlayers[1] = ?John?
/>
<cfset arrPlayers[2] = ?Bob?
/>
<cfset arrPlayers[3] = ?Frank?
/>
<cfset arrPlayers[4] = ?Pete?
/>
<cfset arrPlayers[5] = ?Hank?
/>
<cfset arrPlayers[6] = ?Dave?
/>
<cfset arrPlayers[7] = ?Craig?
/>
<cfset arrPlayers[8] = ?Bill?
/>
<cfset arrPlayers[9] = ?Curly Joe?
/>
Arrays use brackets to indicate the position of the element within the array. By
setting arrPlayers[1] = ?John?, we?re assigning the value of John to the first
array element. This particular array has elements from 1 through 9
(arrPlayers[9]).
Note: If you are familiar with arrays in JavaScript, Java, C++ (to name a
few)...you may expect an array to start at position 0. In ColdFusion, arrays
begin at position 1.
Using the <cfdump> tag, we can get a good visual
representation of our array:
What?s the advantage of using an array, over creating a list? Two things:
1) Array manipulation is quicker/more efficient than list manipulation. This is because lists are position-oriented, while arrays are math-oriented.
That is to say, if we had the list of players, and we wanted to extract the 3rd player (list element), we would use the listGetAt() function:
<cfoutput>#listGetAt(lsPlayers, 3)#</cfoutput>
(notice the name of the variable changed to indicate that it?s a list?not an array)
This will prompt ColdFusion to parse the string (a list, even though it?s made up of multiple items, is still simply one long string), until it arrives at the 3rd position. In a 9 item list, this process will be relatively quick. However, as a list grows, this parsing will take more and more time.
If we wanted to extract the 3rd player from an array?well, we wouldn?t even need to resort to a function:
<cfoutput>#variables.arrPlayers[3]#</cfoutput>
ColdFusion does not have to parse the entire array. It knows exactly where to go (element 3), and goes directly to that element without having to ever touch elements 1 or 2. You can see where this would offer a significant performance increase over lists. Especially in a larger group of data.
2) A list is limited to a one-dimensional string. An array, however, can be multi-dimensional. What if, in addition to the player?s name, we wanted to store the position they play? We are now talking about a 2 dimensional array. This is where people sometimes get intimidated. But in reality, this is nothing more than two 1 dimensional arrays. In reality?it?s a grid. We?ll look at multidimensional arrays next.
2 Dimensional Arrays
If you feel that you have a good understanding of a 1 dimensional array, 2
dimensional arrays should be no problem, as they are simply nested 1 dimensional
arrays.
Continuing on with the baseball player array?what if, in addition to the
player?s name, we also wanted to keep track of the position that player plays?
<cfset arrPlayers = arrayNew(2) />
Again, we use the arrayNew() function?but this time we pass 2 as an argument,
indicating that we want to create a 2 dimensional array.
The code to populate this new array is below, with an explanation following.
<cfset arrPlayers[1][1]
= ?John? />
<cfset arrPlayers[1][2]
= ?First Base? />
<cfset arrPlayers[2][1]
= ?Bob? />
<cfset arrPlayers[2][2]
= ?Second Base?
/>
<cfset arrPlayers[3][1]
= ?Frank? />
<cfset arrPlayers[3][2]
= ?Third Base? />
<cfset arrPlayers[4][1]
= ?Pete? />
<cfset arrPlayers[4][2]
= ?Shortstop?
/>
<cfset arrPlayers[5][1]
= ?Hank? />
<cfset arrPlayers[5][2]
= ?Left Field? />
<cfset arrPlayers[6][1]
= ?Dave? />
<cfset arrPlayers[6][2]
= ?Center Field? />
<cfset arrPlayers[7][1]
= ?Craig? />
<cfset arrPlayers[7][2]
= ?Right Field? />
<cfset arrPlayers[8][1]
= ?Bill?
/>
<cfset arrPlayers[8][2]
= ?Pitcher? />
<cfset arrPlayers[9][1]
= ?Curly Joe? />
<cfset arrPlayers[9][2]
= ?Catcher? />
The length of the array is still 9, even though there are now 18 elements. Each
position simply has 2 dimensions. I described it as a grid earlier. Here is a
visual representation of that grid:
arrPlayers (Array)
| 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | |
| 1 | John | Bob | Frank | Pete | Hank | Dave | Craig | Bill | Curly Joe |
| 2 | First Base | Second Base | Third Base | Shortstop | Left Field | Center Field | Right Field | Pitcher | Catcher |
The numbers on top represent the first dimension. The numbers along the side
represent the second dimension. So following that logic, the value of
arrPlayers[3][2] is ?Third Base? (go to the number 3 on top, and the number 2
down the left). For any value in our array, arrPlayers[x][y], x is represented
by the top row of numbers, and y is represented by the vertical column of
numbers.
And a <cfdump> clearly shows us that our 2d array
is simply a 1d array comprised of a series of 1d arrays:
I?ve only shown the first 3 positions, but it still clearly illustrates the
point that a 2 dimensional array is simply a 1 dimensional array of 1
dimensional arrays.
It is correct to say:
arrPlayers is a 2 dimensional array that has 9 positions
The first dimension holds the ?name? value
The second dimension holds the ?position played? value
We could go even further, and add each player?s age to the array.
<cfset arrPlayers = arrayNew(2) />
<cfset arrPlayers[1][1]
= ?John?
/>
<cfset arrPlayers[1][2]
= ?First Base? />
<cfset arrPlayers[1][3]
= 30 />
<cfset arrPlayers[2][1]
= ?Bob? />
<cfset arrPlayers[2][2]
= ?Second Base?
/>
<cfset arrPlayers[2][3]
= 32
/>
<cfset arrPlayers[3][1]
= ?Frank? />
<cfset arrPlayers[3][2]
= ?Third Base? />
<cfset arrPlayers[3][3]
= 28 />
<cfset arrPlayers[4][1]
= ?Pete?
/>
<cfset arrPlayers[4][2]
= ?Shortstop? />
<cfset arrPlayers[4][3]
= 26 />
<cfset arrPlayers[5][1]
= ?Hank? />
<cfset arrPlayers[5][2]
= ?Left Field? />
<cfset arrPlayers[5][3]
= 31 />
<cfset arrPlayers[6][1]
= ?Dave?
/>
<cfset arrPlayers[6][2]
= ?Center Field? />
<cfset arrPlayers[6][3]
= 33 />
<cfset arrPlayers[7][1]
= ?Craig? />
<cfset arrPlayers[7][2]
= ?Right Field? />
<cfset arrPlayers[7][3]
= 24 />
<cfset arrPlayers[8][1]
= ?Bill? />
<cfset arrPlayers[8][2]
= ?Pitcher? />
<cfset arrPlayers[8][3]
= 22
/>
<cfset arrPlayers[9][1]
= ?Curly Joe?
/>
<cfset arrPlayers[9][2]
= ?Catcher? />
<cfset arrPlayers[9][3]
= 25 />
Very important to note?this is STILL a 2 dimensional array. It might appear at
first that there are 3 dimensions. However, notice that we still only have
brackets [x][y] for each of the 9 positions. Each position holds 3 elements, as
opposed to two. We could add data for the salary of each player?as well as
whether or not they bat left or right. Still, a 2 dimensional array?but would
now have 5 elements in each position.
A visualization of the code above might be in order:
variables.arrPlayers (Array)
| 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | |
| 1 | John | Bob | Frank | Pete | Hank | Dave | Craig | Bill | Curly Joe |
| 2 | First Base | Second Base | Third Base | Shortstop | Left Field | Center Field | Right Field | Pitcher | Catcher |
| 3 | 30 | 22 | 28 | 26 | 31 | 33 | 24 | 22 | 25 |
?and a <cfdump> to illustrate it one more way (still only displaying positions 1-3):
So if we want to know the age of the 8th
player, we output variables.arrPlayers[8][3]. The position played by the 4th
player? variables.arrPlayers[4][2].
Obviously, this wouldn?t be possible with a list. And we have effectively stored
27 separate, unique values in one single variable.
That?s really the basics behind an array, which is what I wanted to demonstrate.
Anything more would push this tutorial out of the beginner?s area, where I would
prefer to keep it. Arrays (and Structures?see part 2 of this tutorial ?series?)
were a difficult concept for me to grasp coming into ColdFusion with no prior
programming experience. I hope that the description above will make it easier
for others in the same situation.
A couple of final thoughts?
Although I only described 1 dimensional and 2 dimensional arrays, ColdFusion
supports up to 3 dimensions. If a 2 dimensional array can be represented by a
grid (as I?ve shown above), then a 3 dimensional array can be represented by a
cube.
ColdFusion arrays are dynamic. This means if you have a 9 position array (for
the sake of simplicity, let?s consider our original 1 dimensional array, that
held the names of the players on the team)?and you remove the element at
position 4, you now have an 8 element array (all elements that followed 4 slide
?up? one position). Some other languages would leave a NULL value at position 4,
and maintain a 9 position array. So this distinction between ColdFusion arrays
and array behaviour in other languages is important to remember.
How would we remove the element at position 4? We would use the arrayDeleteAt()
function. All of ColdFusion?s built-in array functions can be found in your
online documentation, or at
http://livedocs.macromedia.com/coldfusion/6/CFML_Reference/functions-pt06.htm#3473387
If you feel that you?ve got a fundamental understanding of arrays, please check
out Part 2 of this series, which covers Structures.
As always, if there are any questions or any areas that I can clarify for you,
please don?t hesitate to contact me directly, or via the
easycfm.com forums (preferably the
latter, so that others might benefit from the discussion).