Variables in CFML; Indexed Notation

Indexed notation, also called array notation, is somewhat more complex than Dot notation, but can be much more powerful and flexible. Complex data types are assigned, internally, "indexes" or, to put it simply, labels which represent the position of each piece of data in the object. Indexed notation is the only way to access arrays in CFML but can also be used instead of Dot notation to access queries and structures.

Indexed notation takes the basic form of object[index] where "object" is a complex, indexed variable and "index" (always wrapped in square brackets) is the index being referenced. As with Dot notation multiple indexes are required to properly reference nested complex data types. A main feature of Indexed notation is that each index can itself be a dynamic value, a variable, or an expression. This allows for complex looping and access of indexed objects based on any number of decisions or parameters. All of the following examples are legal:

<cfset foo = 2>
<cfset fee = myArray[foo][1]>
<cfset faa = myArray[foo][1 + 1]>
<cfset fii = myArray[1][foo + 1]>
<cfset fuu = myArray[foo][IncrementValue(foo)]>

Arrays

Arrays must always be accessed with Indexed notation. With arrays indexes are always integer values greater than zero (unlike many other languages CFML begins counting array indexes at one, not zero). The index number represents the position of the referenced value in the array.

A one dimensional array can be thought of as a stack of cells and requires only one index to reference any value in it. For example to fetch the third item in the single dimensional array "myArray" you'd use myArray[3].

A two dimensional array (seen as a stack of one dimensional arrays) requires two indexes to reference any cell, or a single index to reference one of the single dimensional arrays. For example, consider the following code:

<cfset myArray = ArrayNew(2)>
<cfset myArray[1][1] = "A ValOne">
<cfset myArray[1][2] = "A ValTwo">
<cfset myArray[2][1] = "B ValOne">
<cfset myArray[2][2] = "A ValTwo">

You could reference the value "A ValTwo" with myArray[1][2] and the value "B ValOne" with myArray[2][1]. Referencing myArray[1] however would return the entire "1" array (the first two values).

Three dimensional arrays (think of them as stacks of two-dimensional arrays) work in much the same way although, of course, you would use three indexes like so myArray[index1][index2][index3]. In common practice three dimensional arrays are little used (although they are very important for some tasks.

Also, although CFML allows you to create arrays of only up to three dimensions you can, of course, place three dimensional arrays as data within other three dimensional arrays. This nesting allows for arbitrarily deep nesting of array dimensions. It can also get incredibly confusing incredibly fast so it's only recommended that advanced programmers tackle such a thing.

Queries

Queries can be accessed with Indexed notation. Query columns are accessed by column name (not a numerical position) while rows are always accessed by numerical position (an integer greater than zero). This takes the form queryName["ColumnName"][RowNumber]. Each of the indexes (row and column) can also be dynamic (variables or expressions).

When using Indexed notation to reference a query column only (no row) in the form queryName["ColumnName"], the object returned (the query column) is considered a one-dimensional array and can be treated as such. This is a very powerful aspect of CFML that's often overlooked. For example consider a column called "Visits" in the query "myQuery" which lists the total number of visits made to a site per day (each day in the sequence being a row). Often a looping count is constructed that tallies a total (for display at the bottom of a table for example). However, remembering that we can access the column as an array we could also more easily use the "ArraySum()" function like so:

<cfset TotalVisits = ArraySum(MyQuery["Visits"])>

Also accessing queries via Indexed notation can easily do away with many of the unnecessary Evaluate() functions being used to access them via Dot notation. For example the statements:

<cfset curCol = "Visits">
<cfset myVar = Evaluate("myQuery.#curCol#[1]")>

Could be written without the Evaluate() function like so:

<cfset curCol = "Visits">
<cfset myVar = myQuery[curCol][1]>

Not only is the second block of code easier to read and understand, but over large loops and recordsets the performance improvement can be significant.

Structures

Indexed notation for structures shares many similarities with Indexed notation for queries. It takes the form structName["KeyName"] where "KeyName" is any valid key in the structure. As with queries the value used in the index can be a simple string, a variable or any other expression.

Like queries an understanding of how to reference structures via Indexed notation can often save significant amount of time and processing that would otherwise require the Evaluate() function. For example the following code loops over a simple structure and returns the values within it:

<cfloop collection="#myStruct#" item="KeyName">
<cfoutput>#Evaluate("myStruct.#KeyName#")#</cfoutput>
</cfloop>

However using Indexed notation allows us to do the same job cleaner, quicker and with less typing:

<cfloop collection="#myStruct#" item="KeyName">
<cfoutput>#myStruct[KeyName]#</cfoutput>
</cfloop>

When using Dot Notation ColdFusion automatically converts key names to uppercase when creating keys. With indexed notation however the case used when creating keys is remembered and honored. This may be important when working with supporting, case-sensitive languages like JavaScript and XML. Indexed notation can also be used to create non-standard, illegal key names. If possible we recommend that you don't do this, but often (particularly when dealing with outside datasources) you may be forced to adopt such keys. Some examples of this:

<cfset myStruct["5"] = 10> <cfset myStruct["This Key has Spaces"] = 10> <cfset myStruct["@"] = 10>

15 Current Sessions; Time: 02:02:55 06-01-2009; Tick: 985