ColdFusion 101: Sorting Directory Paths in ColdFusion

A reader asked how they could sort a set of directory paths in ColdFusion. The answer isn't that complex, and like most things in ColdFusion it can be done multiple ways. I thought it would be interesting to demonstrate as it may show a few tags/functions that beginners may not be familiar with.

First off - let's look at the paths the reader wants to sort:

/banana/someFile.txt
/banana/someOtherFile.txt
/banana/dog
/apple
/
/banana/dog/someFile.txt
/banana/cat
/banana
/orange
/banana/dog/someOtherFile.txt
/banana/dog/yetAnotherFile.txt
/orange/hamster/horse/someFile.txt
/watermelon

Imagine you got data like this. It could be in a file by itself. It could be the result of a external program, or in an email. Your first question may be - how do I turn what looks like an obvious list into a real ColdFusion list? Let's first see a simple way to turn a text block into a ColdFusion variable. Normally you wouldn't have to worry about this. The data would come from a file for example. In my case the text was in an email. I cut and pasted the text into a CFM file and simply surrounded it with cfsavecontent tags:

<cfsavecontent variable="paths">/banana/someFile.txt
/banana/someOtherFile.txt
/banana/dog
/apple
/
/banana/dog/someFile.txt
/banana/cat
/banana
/orange
/banana/dog/someOtherFile.txt
/banana/dog/yetAnotherFile.txt
/orange/hamster/horse/someFile.txt
/watermelon
</cfsavecontent>

By simply wrapping the text in the cfsavecontent tags, the text is copied into a variable called "paths." So I know I'm going to need to sort these paths, but right now my data is just one big blob of text. How can I turn into something more manageable?

Well, don't forget that ColdFusion can treat any string as a list. A list is any text that has delimiters. Typically a list will look like so: Jacob,Lynn,Noah. In this list, there are three items delimited by a comma. However, other characters can be considered a delimiter as well. In this case, we can consider the line feeds and carriage returns (the breaks basically) as delimiters. ColdFusion lets us work with lists containing multiple delimiters. All I need to do is use the listToArray function to treat the string as a list and turn it into an array:

<cfset aPaths = listToArray(paths, "#chr(10)##chr(13)#")>

All this line says is to split the string whenever a chr(10) or a chr(13) is found. If any combination of them is found, it is considered a delimiter. So far so good? So how hard is it to sort the array? All we need is one more function: arraySort. The following code will take the original paths string, turn it into an array, dump it, then sort the data and dump it again:

<cfset aPaths = listToArray(paths, "#chr(10)##chr(13)#")>
<cfdump var="#aPaths#">

<cfset arraySort(aPaths, "textnocase")>

<cfdump var="#aPaths#">

P.S. Notice something odd about the arraySort function? Unlike most ColdFusion functions, arraySort operates on the data you send to it and returns a status instead of the data it changed. If I were to dump the result of the arraySort I would get either a YES or NO, representing the result of the sort operation. If for some reason you needed to keep the original around, you would need to make a copy first.

For more information: List functions and Array functions.

Archived Comments

Comment 1 by Ryan Guill posted on 8/30/2005 at 12:40 AM

One thing worth noting, and I cant think of which functions they are off the top of my head at the moment, but there are list functions that take a delimiter attribute only if you specify mulitple charachters in the delimiter it uses each character as a delimiter not the group of characters as a whole. I belive when looping over a list it is that way for example.

Comment 2 by Raymond Camden posted on 8/30/2005 at 12:43 AM

I may not be reading you right. Afaik, _all_ list functions treat XYZ, when passed as the delimiter, as a list of delimiters where each char is a delimiter.

Comment 3 by Ryan Guill posted on 8/30/2005 at 12:46 AM

maybe it is all of them then. There has just been times I wished there was a way to use a group of characters as a delimiter, such as "," or ,[space] for instance.

So what youre saying is then is when you use #chr(10)##chr(13)# as a delimiter, it is delimiting on chr(10) OR chr(13) right? not both together as one delimiter? guess that would work as well...

Comment 4 by Raymond Camden posted on 8/30/2005 at 12:51 AM

Correct. I hope it was clear. If not, the comments here should clarify it. As it stands, there is a UDF at CFLib that will split a string using a multicharacter string as a delimiter. I think it's called Split in fact.

Comment 5 by Ryan Guill posted on 8/30/2005 at 12:54 AM

Yeah I think you were clear. I was actually thinking that some functions would use a multichar delimiter but most wouldnt, but I guess thats right. I dont mess with lists a whole lot so I cant ever remember for sure.

When it does come time for me to need a multichar delimiter, I usually just do a replace() on the list and change the multichar to another delimiter such as a pipe |