Following up on my series of blog entries from last week, here is another gotcha you want to look out for when using ColdFusion arrays. When defining an array in ColdFusion, you typically set them starting with 1 and ending with some number:
<cfset arr = arrayNew(1)>
<cfloop index="x" from="1" to="10">
<cfset arr[x] = randRange(1,100)>
</cfloop>
This creates an array with items in indexes 1 to 100. But - consider this example:
<cfset arr = arrayNew(1)>
<cfloop index="x" from="1" to="10">
<cfset arr[randRange(1,100)] = x>
</cfloop>
Now this is a bit convoluted, but this code example assigns values based on a random index. It will create 10 array values in indexes from 1 to 100 (and it may even do the same index twice).
What happens if you try to loop over this array? The normal way to loop over an array is to use arrayLen:
<cfloop index="x" from="1" to="#arrayLen(arr)#">
If you run this code on the array we just created, you will get an error because the indexes aren't all defined. What about isDefined()? It won't work on arrays. So what do you do?
One solution is to try/catch:
<cfloop index="x" from="1" to="#arrayLen(data)#">
<cftry>
<cfoutput>Item #x# is #data[x]#<br /></cfoutput>
<cfcatch></cfcatch>
</cftry>
</cfloop>
Another option is to use a UDF that wraps up the same logic. You can find arrayDefinedAt() at CFLib. Here is an example of code that uses it:
<cfloop index="x" from="1" to="#arrayLen(data)#">
<cfif arrayDefinedAt(data,x)>
<cfoutput>Item #x# is #data[x]#<br /></cfoutput>
</cfif>
</cfloop>
Lastly, you can just wait for Scorpio! One of the announced features is an arrayiIsDefined function. Ok, most likely you can't wait for Scorpio, but it's nice to know Adobe took care of this problem.