Understanding Arrays and Structures in ColdFusion

Part 3 of an Ongoing Saga:

(if you have not yet read parts 1 and 2 of this tutorial, I strongly urge you to do so prior to reading this final chapter).

If you?ve made it this far, congratulations! You know what an array is, and you know what a structure is. You can create a 1d or 2d array, and you can create a structure and nested structures.

This final chapter will show you how to actually use arrays and structures?and how to use the two together in order to overcome the limitations of each.

If you?ve been with us through parts 1 and 2 of this tutorial, you remember that we were using the players on a baseball team to illustrate arrays and structures.

The array looked like (shortened for brevity):

<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 />

The problem was accessing the age of the second baseman required somewhat cryptic code:

<cfoutput>#arrPlayers[2][3]#</cfoutput>


We then delved into structures. A structure holding player info looked like:

<cfset stPlayer = structNew() />

<cfset stPlayer.position =
?First Base? />
<cfset stPlayer .age =
30 />
<cfset stPlayer.salary =
200,000 />
<cfset stPlayer.bats =
?right? />

This allowed us to use code that was easy to understand in outputting values:

<cfoutput>#stPlayer.age#</cfoutput>

Very intuitive?but we can only create one structure per player. How can we create one single variable that will hold information about all members of the team?

An array of structures.

We will create a 1 dimensional array, called arrPlayers. We did this waaaay back in the first part of this tutorial, so it should be cake for you now.

<cfset arrPlayers = arrayNew(1) />

In the first array position, we want to store all of the information about our first baseman, John. As we saw in the previous chapter, the best way to do this is with a structure. So in position 1, we create a structure:

<cfset arrPlayers[1] = structNew() />

And to populate that structure:

<cfset arrPlayers[1].playerName = ?John? />
<cfset arrPlayers[1].position =
?First Base? />
<cfset arrPlayers[1].age =
?30? />

Before we go any further, let?s take a look at what we?ve just created:



You can see the array (indicated in a <cfdump> by a green table), which contains a structure (indicated in a <cfdump> by a blue table).

So?<cfoutput>#arrPlayers[1].playerName#</cfoutput> gives us an output of John. Again, much more straightforward than storing all of the information in an array. Plus, we can now add more players:

<cfset arrPlayers[2] = structNew() /> // creates an empty struct

<cfset arrPlayers[2].playerName = ?Bob? /> // populates the player?s name
<cfset arrPlayers
[2].position = ?Second Base? /> // populates the player?s position
<cfset arrPlayers
[2].age = ?32? /> // populates the player?s age

We?ve now created a second position in our 1 dimensional array. We populated it with a new structure, and then populated the structure with the relevant information. We simply continue to do this for each player on the team, and ultimately we end up with:



This variable, even though it is a series of nested complex variables, is still one single variable. Furthermore, we can easily get at the information we want.

<cfoutput>#arrPlayers[4].age#</cfoutput> is clearly going to return 26.

In fact, let?s output all of the player information. An array without a loop is like a car without an engine. You?ll find that as you use arrays more and more, you?ll most frequently be looping over them.

1. <cfoutput>
2. <table border="1">
3.  <tr>
4.    <td style="font-weight:bold;">Player Name&nbsp;&nbsp;</td>
5.    <td style="font-weight:bold;">Position&nbsp;&nbsp;</td>
6.    <td style="font-weight:bold;">Age</td>
7.  </tr>
8.  <cfloop from="1" to="#arrayLen(arrPlayers)#" index="i">
9.  <tr>
10.   <td>#arrPlayers[i].playerName#</td>
11.   <td>#arrPlayers[i].position#</td>
12.   <td style="text-align:right;">#arrPlayers[i].age#</td>
13. </tr>
14. </cfloop>
15. </table>
16. </cfoutput>

Obligatory line-by-line breakdown:

1. Open a <cfoutput> tag. I frequently see people put their <cfoutput></cfoutput> inside of a <cfloop>. It?s much better to place the <cfoutput>?s outside of the loop. This way the tag is only called once, rather than once for each iteration of the loop.
2. Create an HTML table
3. Create a new table row
4. A column heading (Player)
5. A column heading (Position)
6. A column heading (Age)
7. Ending a table row
8. Our loop. We use the ColdFusion function arrayLen() to determine the number of times we will loop. In this instance, #arrayLen(arrPlayers)# will evaluate to 9, as we have 9 array positions.
9. Create a new table row for each iteration of the loop.
10. Output each player?s name in a table cell. #arrPlayers[i].playerName# will accomplish this. Bear in mind that the value of i will increment with each iteration of the loop.
11. Output each player?s position in a table cell.
12. Output each player?s age in a table cell.
13. Close the table row for each iteration of the loop.
14. End loop
15. Close table
16. Close <cfoutput>

And when we view this in a browser, we see:



Another example of a practical use of arrays and structures is a shopping cart.

This is not meant to be a full-fledged shopping cart tutorial, so I will be explaining just enough to demonstrate the array/structure aspect.

Assume a session variable called session.shoppingCart. session.shoppingCart is initialized as a new array (this would be done within your Application.cfm template). If you?re not familiar with session variables at this point, that?s ok. For the purposes of this demonstration, simply realize that a session variable is persistent?it can be accessed from any page within an application.

Each client will start off with their own instance of session.shoppingCart?an empty array.

<cfdump var=?#session.shoppingCart#?>


Assume each product has a product ID, a color, a size, and a price.

For each item that the client places into the cart:

1. <cfset temp = arrayAppend(session.shoppingCart, structNew())>

2. <cfset session.shoppingcart[arrayLen(session.shoppingcart)].productID = 52>
3. <cfset session.shoppingcart[arrayLen(session.shoppingcart)].color = "red">
4. <cfset session.shoppingcart[arrayLen(session.shoppingcart)].size = "XXL">
5. <cfset session.shoppingcart[arrayLen(session.shoppingcart)].quantity = 2>


1. First, we create a new structure to hold the information for the item that the user is placing in the cart. We do this with an arrayAppend() function. arrayAppend() will add a new position at the end of a given array. It returns TRUE or FALSE, which is why we use a temp variable.

If we have 3 items in the cart, arrayAppend(session.shoppingCart, structNew()) will create a 4th array position and populate it with an empty structure.

2. Because we don?t necessarily know what position we?re going to be inserting the new item into, we do not reference array positions using session.shoppingcart[4]. Instead, we use the arrayLen() function to create a more dynamic method. arrayLen() returns the length of the array?which will always point to the last position (which is where we?re inserting the new item into the cart). In lines 2 ? 5, we populate the structure that we just created in the last array position with productID, color, size, and quantity.

<cfdump var=?#session.shoppingCart#?>


Now, let?s say the user adds another item. We would re-use the same code, inserting the appropriate values. Assume the user has 3 products in the cart.

<cfdump var=?#session.shoppingCart#?>


Want to know how many items are in the cart at any given time? Simply loop over the array, and add the quantity values together:

<cfset totalItems = 0>
<cfloop from=
"1" to="#arrayLen(session.shoppingcart)#" index="i">
   <cfset totalItems = variables.totalItems + session.shoppingcart[
i].quantity>
</cfloop>


You have: <cfoutput><strong>#variables.totalItems#</strong></cfoutput> items in your cart

Let?s say the customer decides that green isn?t his (or her) color. They want to remove the 2nd item from their cart.

<cfset temp = arrayDeleteAt(session.shoppingcart, 2)>

Because the ColdFusion function arrayDeleteAt() returns TRUE or FALSE, we must use a temp variable. Beyond that, the function requires 2 arguments. The array to be manipulated, and the position to remove.

Running the arrayDeleteAt() function leaves us with:



What is important to note here is that by removing position 2, everything after position 2 shifts up. What was an array with a length of 3 is now an array with a length of 2.

Some languages would have left the array with 3 positions, and a null value at position 2. Because ColdFusion arrays are dynamic in nature, they will shrink to accommodate the removal of an element.


Final Thoughts

I urge you to familiarize yourself with ColdFusion?s built in array functions and structure functions. If you installed the ColdFusion documentation during your CF install, everything you need is on your server (by default, located at http://localhost/cfdocs/).

I realize that there are likely still quite a few questions. Arrays and structures, while not really difficult subjects, do represent the ?next level? of understanding not only ColdFusion, but programming concepts in general. I?ve tried to keep these tutorials as simple as possible?yet as comprehensive as possible, without turning them into advanced level tutorials.

I don?t expect you to feel that you?re ready to sit down and write a shopping cart application in the next 20 minutes. I *do* expect that you have a general understanding of an array and a structure?and how to use both (individually and together). I expect that you will build on this foundation by experimenting with your own code, as well as posting questions to the forums, or e-mailing me when you?re stuck.

If there are lingering questions?ask. If you feel another tutorial (perhaps more intermediate to advanced level) is warranted?suggest it.

I look forward to hearing from you.

CJ

About This Tutorial
Author: Charlie Griefer (CJ)
Skill Level: Beginner 
 
 
 
Platforms Tested: CF5,CFMX
Total Views: 171,121
Submission Date: August 11, 2003
Last Update Date: June 05, 2009
All Tutorials By This Autor: 15
Discuss This Tutorial
  • Great tutorial series. Great style. You seem to be a natural teacher, so keep em coming!

  • That light bulb you see glowing ever so brightly over my head is the result of the "AHA" that I uttered as I poured over this tutorial. Thanks for a well thought out and easily understandable series of tutorials on Lists, Arrays and Structures!

  • Christine: The answer is that you cannot easily sort an array of structs. Yes, CF has a built in ArraySort() function, but that only works on 1 dimensional arrays that contain -simple- values (structures, like arrays, are complex datatypes). However, all is not lost :) see http://cflib.org/udf.cfm?id=359&enable=1 cflib is an amazing resource. when there's not a built-in function to do what you want, it should be the first place to check. I've run some sample code using this UDF and it seems to work pretty flawlessly. Hope that helps.

  • In the example table with Player Name, Position, and Age; could you sort by age or name?

  • Thanks for all three. Superbly written, very easy to understand. Thanks. Tristan

  • Great explanation - easy to understand. Thanks a lot.

  • This is exactly what I am looking for. Thank you very much.

Advertisement


Website Designed and Developed by Pablo Varando.