Ben Nadel
On User Experience (UX) Design, JavaScript, ColdFusion, Node.js, Life, and Love.
I am the chief technical officer at InVision App, Inc - a prototyping and collaboration platform for designers, built by designers. I also rock out in JavaScript and ColdFusion 24x7.
Meanwhile on Twitter
Loading latest tweet...
Ben Nadel at the jQuery Conference 2010 (Boston, MA) with:

Ask Ben: Looping From 'A' To 'Z' In ColdFusion

By Ben Nadel on

Is there an easy way to list from a to z in the alphabet?

There are few ways to loop over the letters A to Z using ColdFusion. Some are more complicated than others, but perhaps more useful. Let's start off by looking at traditional list loop. If you want, you could create a list of all letters between A and Z and loop over that:

  • <!--- Loop over letters as a list. --->
  • <cfloop
  • index="strLetter"
  • list="A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z"
  • delimiters=",">
  •  
  • #strLetter#
  •  
  • </cfloop>

This method is VERY simple and VERY straightforward. But, on the other hand, it is prone to error. Are you sure you wrote down all the letters? Did you miss any?

The next method would be to use an index loop based on the ASCII values of the letters from A to Z. The ASCII values are such that going from A to Z is an incrementing value list.

  • <!--- Loop over ascii values. --->
  • <cfloop
  • index="intLetter"
  • from="#Asc( 'A' )#"
  • to="#Asc( 'Z' )#"
  • step="1">
  •  
  • <!--- Get character of the given ascii value. --->
  • <cfset strLetter = Chr( intLetter ) />
  •  
  • #strLetter#
  •  
  • </cfloop>

This reduces room for error since you don't have to write out all of the letters. But on the flip side, you have go through the extra step of converting the ASCII value back to a character value, and it might not be as straight forward to someone reading the code.

Sometimes, what I like to do is load the letters right into a query. I find a query loop more intuitive some reason and it is much more reusable than a standard list.

  • <!--- Create a query for the letters. --->
  • <cfset qLetter = QueryNew( "" ) />
  •  
  • <!--- Add the letters (one per record) to the query. --->
  • <cfset QueryAddColumn(
  • qLetter,
  • "name",
  • "CF_SQL_VARCHAR",
  • ListToArray(
  • "A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z"
  • )
  • ) />
  •  
  • <!--- Loop over letter query. --->
  • <cfloop query="qLetter">
  •  
  • #qLetter.name#
  •  
  • </cfloop>

This is clearly the most complicated of the three options, and certainly the least straight forward... but, I once you get the letters into the query, they are highly reusable. The physical CFLoop tag is much more simple, and it's more intuitive to scope the letter (which will reduce naming conflicts).

In practice, I tend to go with the ASC() to ASC() value index loop. It is a good combination of clear-to-read code and reduced risk of error.



Reader Comments

Thanks for the the answer. I like number two. I'm not even going to think about three right now. Basics now, advanced later.

Reply to this Comment

Firstly... Ben: your blog is usually quite interesting but today's tutorial is a bit torturous. Manually write out a list only to convert it into an array before converting it again into a query? Jesus. What a shambles. I realise you're just demonstrating... err... *something*... but god what a shite suggestion.

Michael. Hang your head in shame. I normally respect what comes out of your brain, but your example is on a par with Ben's (last) one. You're trying to be clever with your usage of for() expressions, I can see that; but have just come up with rubbish. It's both poor code, and poor logic behind the code in the first place.

You're claiming your own solution only needs "transformation" on increments. Yes. TWO transformations for each iteration. ASC() and CHR(). Applying some sense, one would evaluate the boundaries of the loop ONCE, and then iterate over them, rather than reevaluate them each time (despite knowing the answer of that reevaluation already).

For (i="M";i NEQ "P"; i=Chr(Asc(i)+1))

Get rid of all that sh*t.

iStart = asc('M');
iStop = asc('P');
for (i=iStart; i le iStop; i=i+1)//etc

For one, it's easier to read; for a second: it's better code; a trivial third is that it would be infinitesimally faster (which is not a sensible consideration).

--
Adam

Reply to this Comment

(and, much as it pains me to advocate CFML over CFscript... doing that in a <cfloop> would be better still, and gets us back to Ben's second suggestion).

--
Adam

Reply to this Comment

Which is why I gave the link so people can see the example in context. I'm not saying its what should be done, it's just what can be done in CFSCRIPT:
"8.6 The variable set and the end operation do not have to be numeric in nature. This example shows how to set the initial value to a character, increment the character and check it to see if the loop should end. It will output the letters M, N and O seperated by a space."

A CFLOOP can only compare numbers while a for loop can compare any ascii value. That's the bottom line of my original entry and of my post.

Reply to this Comment

@Michael,

I happen to like your solution, and unlike Adam, I do find it readable. It emphasizes the FROM and TO parts of the loop. Frankly, the incremental portion doesn't even need to be as readable if you understand what the loop is doing overall.

And, from what I can see, Adam's loop example is doing pretty much the same as one of my examples, just breaking it out into ??more?? readable steps.

@Adam,

Admittedly, I wouldn't go for option 3 most of the time. But, there are times where having the letters in a query is awesome. Think about taking a query returned from the database and grouping it based on letters? (think last name). Having the whole alphabet in a query would allow you do an easy GROUP BY and find letters where there were no matching records.

On top of that, the query is the most easily reusable. You could loop over it at the top of the page (outputting a list of letters as links or anchors) and then do the same thing on the bottom of the page, and use it to join to another query. It's more complex upfront, but it becomes much more flexible and reusable in the long run.

The best solution is going to depend on the situation.

Reply to this Comment

Hi All,

For all that previous ways, the best way I like to use is this:

The best solution is going to depend on the situation.

Ameen

Reply to this Comment

I was trying to find an elegant way to create an A-Z list, and this blog entry came up in a google search.

I ended up using the third solution so that I could loop over the array and compare to records in my database that had data under them, and then used the results to create named anchors for my page.

Thanks Ben!

Reply to this Comment

Hi .. I like this Methodology Good!

* <!--- Loop over ascii values. --->
* <cfloop
* index="intLetter"
* from="#Asc( 'A' )#"
* to="#Asc( 'Z' )#"
* step="1">
*
* <!--- Get character of the given ascii value. --->
* <cfset strLetter = Chr( intLetter ) />
*
* #strLetter#
*
* </cfloop>

Little Tweaks to set in a select Box like this

<select name="class" id="class" tabindex="1">
<cfloop index="intLetter" from="#Asc('A')#" to="#Asc('F')#" step="1">
<!--- Get character of the given ascii value. --->
<cfset strLetter = Chr( intLetter ) />
<cfoutput>
<option value="#strLetter#">#strLetter#</option>
</cfoutput>
</cfloop>
</select>

Cheers

Reply to this Comment

One thing to mention regarding the difference between method 1 and 2.

Method 2 is definitely more straight-forward, but it assumes a Latin alphabet. It will produce problems with any modified Latin alphabet such as French, Spanish and in fact most European languages other than English.

So for those who aim to support multiple languages, method 1 is probably better for those purposes. Of course, if the only target language is English, there's nothing wrong with the 2nd one.

Just throwing it in there! Thanks, Mr. Nadel!

Reply to this Comment

@Helgi,

That's a good point. I'm not too familiar with how people go about dealing with internationalization (i18n). I think a lot of times, people use "resource packs" to abstract the language being used. Perhaps this kind of a list could be moved to a resource pack.

Reply to this Comment

I usually opt for a cfscript and looping solution. This time, since I'll be using this snippet of code in several places throughout my "lightweight" site, I decided to create a hard coded list and put it in the application scope.

Unlike Ben, I feel really confident in my ability to create a comprehensive and accurate list of letters of the alphabet. (Yeah, I'm just teasing you, Ben!)

I can put initalize this in the application.cfc in the onApplicationStart method. I can then forget about it until I need to use a list of letters.

1) It's fast enough.
2) It's not a memory hog.
3) It's reusable.
4) It's easy to read.
5) It's easy to update (if and when we add to or remove from letters of the alphabet).

<cfscript>
APPLICATION.GeneralData = structNew();
APPLICATION.GeneralData.aThroughZ = "A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z";
</cfscript>

Thanks for the conversation and assistance, Ben (et al).

Reply to this Comment

Post A Comment

You — Get Out Of My Dreams, Get Into My Comments
Live in the Now
Oops!
Comment Etiquette: Please do not post spam. Please keep the comments on-topic. Please do not post unrelated questions or large chunks of code. And, above all, please be nice to each other - we're trying to have a good conversation here.