Wednesday I blogged about ColdFusion arrays and today I got permission to mention another new feature in ColdFusion 8 - Array-based CFLOOP. In the past you would loop over an array like so:
<cfloop index="x" from="1" to="#arrayLen(arr)#">
<cfoutput>#arr[x]#<br /></cfoutput>
</cfloop>
ColdFusion 8 adds a new array attribute to cfloop so you can do this instead:
<cfloop index="x" array="#arr#">
<cfoutput>#x#<br /></cfoutput>
</cfloop>
I don't think this has been shared yet publicly, so enjoy, and remember that I was given permission to share this. This weekend I think I'll resurrect my 'Known Facts' blog post and update it with all the juicy bits that have been revealed lately.
Archived Comments
Does this kind of loop have the same problem with missing indexes as you mention in your recent post, or will it correctly skip over missing indexes?
I'm going to tread lightly due to NDA.
So I will say this. If it DOES have the bug, you can bet that I tested and filed a bug report since this has been in my mind the last week.
Nice feature. thanks for sharing....
The second example outputs the value of the index x and not the value of the array at the index x, or am I missing something ?
Sorry if it wasn't clear. It outputs the value of the array at index x.
What about the value of the index?
That means if you want to know at which index you're up to, you have to create a variable and increment it at each iteration. 'x' is not the index even if in the cfloop tag the value of index attribute is 'x'... It's a bit confusing ...
Thanks for sharing Ray
I don't see how it is confusing. It is merely a simpler way to loop over an array. If you don't need to know the numerical index, this is as simple as you can make it.
dig it
I don't like the syntax.
I guess it's the same format as a list loop, but I still wish they'd used item="foo" rather than index="foo"
Especially in this case, since thearray index is a number, and the index="x" actually assigns arrya VALUES to "x"
Using "index" as the attribute name in this new implementation is not reflecting what an index should be in an array.
The attribute "index" is set to 'x' but the index of your array in the loop is not 'x'. I find it confusing and not intuitive. Why not using an attribute name like 'arrayVal' ? .. . Rick is probably right, to keep the same format as the list loop. Anyway I'm just happy to see that the language is getting some more "vocabulary"... even if there are a few imperfections.
Ray,
Are we able to speak about this now?
Um, what do you mean? To say more about it? I'd probably not, just to be on the safe side of the NDA.
Ok,thanks!
this work with a 2D array?
<cfloop index="x" array="#arr#">
<cfloop index="y" array="#x#">
#y#
</cfloop>
</cfloop>
Finally, since I started using CF I've been wondering where this function was...
Next you'll be telling us there shall be a clean way to get the number of affected rows from INSERT/UPDATE/DELETE SQL statments (oh please please please).
Guys, I'm not going to answer anymore as I want to be sure I stick to the NDA. :)
Ray,
I'm assuming in a 2d array it would effectively pass the reference to the second array as this is the 'value' within the array at that time.
<cfloop array="#arr1#" index="arr1index" />
<cfloop array="#arr1index#" index="arr2index">
This then implies that any value assignment on arr2Index would actually effect the content of the array after the looping. Yes?
Ben Scott,
To get the number of affected rows is DB dependent feature. If you need this feature, it's very much something specific to a DB.
If you need this information, then I would suggest you write CRUDs inside stored procs.
Adam
I wrote a custom tag like this using <cfexit method="loop" /> within my custom tag template. Its quite easy to roll your own with more features.
My syntax was:
<loop:array array="#myArray#" element="e" index="i">
</loop:array>
Where 'e' is the variable at the current index, i. (index is optional and element defaults to 'element').
One other handy feature of my tag is when its finished looping, it removes references to the element and index when it's done, saving you from having to var scope the element and index if you were in a CFC instance. You can avoid cleanup using the cleanup="true|false" attribute.
Naturally, I did one for structures as well:
<loop:struct struct="#myStruct#" key="k" value="v" cleanup="true">
</loop:struct>
Thanks for the post I forgot the index, this helped!
I'm new to arrays, just learning the basics. So from this, "x" doesn't actually mean anything, its just creating 'something' to put your looped arrays into?
just trying to work out the job of the x
Correct.
Is there a good way to go over a multi-dimensional array?
I would assume that this would do it-
<cfloop array="allResults" index="i">
<cfoutput>
<cfloop array="allResults[i]" index="q">
</cfloop>
</cfoutput>
</cfloop>
This syntax seems nice at first, but then you realise that you miss out on having the current index value.
It's really not that much more effort to use the standard way:
<cfset local.arrayLength = arrayLen(local.array) />
<cfloop index="local.i" from="1" to="#local.arrayLength#">
##local.arrayLength[local.i]#<br />
</cfloop>
At least you can see what's going on and manipulate the values whenever you like.
:)
well more is better. Now that we have the standard way and CF8 way we can choose which one to use. Sometimes you don't need the current index value, sometimes you just need to loop over the array to do something just like what I just did, cool!