Yes, the title is a mouthful. But unfortunately with classic ASP, trying to make sense of an unsorted array is much worse. It is quite often the case, especially when retrieving data from a database, that it may end up in an array which is not ordered perfectly, perhaps due to incorrect data type settings. And of course, ASP would provide us with no intrinsic array sorting mechanisms. This article will explain how to take the array of that data, and hand it off to a function to sort it based on whichever dimension you specify, also with the ability to handle various data types.
Contributed by Justin Cook Rating: / 69 June 09, 2004
I don't especially enjoy sorting laundry. It's boring, and feels somewhat pointless, but at least it's easy to do. It would not be nearly as easy for a web application to sort your laundry. Though it would be far more willing to do work, it just wouldn't understand what laundry is, why it needs to be sorted, and in what order. And as it turns out, if you're using ASP, an array of any type may as well be laundry, because there's no intrinsic way to sort arrays, no matter how simple it may be.
The first time I ran across this issue was with an array of dates. The dates were for events, and all the event information was stored in a database. Normally it wouldn't be an issue retrieving the dates in a properly sorted result set; I could just specify an ORDER BY clause in the SQL statement, which I tried. But the problem here was that the table the events were in was exceedingly normalized. Instead of having separate fields for the date, event title, and other attributes, I had one field called 'content' and another field to identify the type of content it is. That means that every field, every date, every time was stored as the generic type of text.
So I would go about retrieving the data, trying to order it properly, and it worked well for the most part. But when you treat a date as text, funny things happen. Though you and I know that October is farther away than February, a database holding the values as text does not. You see, October would be '10-01-2004', and February would be '02-01-2004', which looks like a larger text value than the first, and when you dump the results into the array you get one funky calendar.
As you can guess, people did not derive extreme pleasure in the application telling them that events in October were now happening at the beginning of the year, so something needed to be done. I had dumped all the data for the events into a multi-dimensional array, so the first thing I did was consult some ASP documentation on how to sort arrays. Much to my chagrin there was nothing to be found. So, I was forced to go it alone, hack out some method to do my sorting, the results of which I share with you today.
The function that I'll show you is built to handle multi-dimensional arrays and sort in an ascending fashion (least to greatest). Both of these can be changed.
The reason for handling multiple dimensions is simply that it happens many times those are the arrays we have and have to sort. Also, it's easier to handle the more complex issue of multiple dimensions in this tutorial, and let you dissect the function if you need to use it for a simple, one-dimensional array at any time.
Also, if you feel the need to sort things in descending order (greatest to least), you could also do that after dissecting the code. After I explain the full code, I'll explain how to do this; it just doesn't make a lot of sense to do it at this point!
Anyhow, without further delay, I will now move on to the function, what you've all come here to see.
The Code
Ok, so let's assume that we have an array that looks like this:
It could be sorted by simply handing it off to the arraySort() function, specifying which dimension to sort it by (in this case the date).
ArEvents = arraySort( arEvents, 1, true )
And then here's the function that's responsible for it all.
'================================================== function arraySort( arToSort, sortBy, compareDates ) '==================================================
Dim c, d, e, smallestValue, smallestIndex, tempValue
For c = 0 To uBound( arToSort, 2 ) - 1
smallestValue = arToSort( sortBy, c ) smallestIndex = c
What's happening here is that we're going through the array one item at a time. With each item, we'll use the sortBy parameter, find the current item, and set the smallest value and index placeholders to the current item. Then we take these items, or placeholders, and compare them to EACH item in the array and look for a smaller value.
For d = c + 1 To uBound( arToSort, 2 )
if not compareDates then
So if the compareDates flag has been set to false, the function will try to compare the values as strings using the inbuilt strComp() function of ASP. Now, don't be too worried about numbers, they will be handled perfectly with this function as well. When we use the strComp() function, it will produce a -1 if the compared string (the first parameter) is smaller, a zero if they're equal, and a 1 if it's larger/greater. In this case, as we're sorting depending on smaller values, we would then set the placeholders to this value and index, if we find that it is indeed smaller. Now you're probably beginning to see where modifications could be made to sort in a descending order.
if strComp( arToSort( sortBy, d ), smallestValue ) < 0 Then smallestValue = arToSort( sortBy, d ) smallestIndex = d End if else
So here we've got the code to handle dates, if the compareDates flag has been set to true. Of course we first check and ensure that we truly are dealing with dates. If not, we recurse, and come back through just comparing strings.
If we have genuine dates, we proceed with our checking, by using the ASP dateDiff() function. Similar to strComp(), this function produces positive or negative integers; however, they're based on the difference in the time frame you specify, and we will specify days (“d”).
if not isDate( smallestValue ) then arraySort = arraySort( arToSort, sortBy, false) exit function else
if dateDiff( "d", arToSort( sortBy, d ), smallestValue ) > 0 Then '=== no carriage return
smallestValue = arToSort( sortBy, d ) smallestIndex = d
End if end if end if Next
Now, we're finished checking the whole array for this specific item, and before we move on the next, we see if anything smaller has been found. If so, then we'll swap the current item for the smallest item found. And of course, since we're dealing with multiple dimensions, we have to loop through them all, and swap all of them, to make sure that we maintain the complete array.
if smallestIndex <> c Then For e = 0 To uBound( arToSort, 1 ) tempValue = arToSort( e, smallestIndex ) arToSort( e, smallestIndex ) = arToSort( e, c ) arToSort( e, c ) = tempValue Next End if
So that is the wonderful, magical function with all of its very limited glory. If you decide you want to try sorting in the reverse direction (descending), then you've probably already figured out where you need to add code. If not, I'll give you a hint: it is only a matter of passing in another parameter to the function (the direction), and a few control flow statements to set the placeholders in the array to be minimum OR maximum values. You then just change the dateDiff() and strComp() lines to look for inverse integers (greater than zero instead of less than, and vise versa), depending on the direction parameter. And there you will have it, one awesomely complete array sorter.
Most people ask me for the code all in one piece, because they don't like gathering bits and pieces between explanations, so here's the code for the function all in one piece:
'============================================== function arraySort( arToSort, sortBy, compareDates ) '==============================================
Dim c, d, e, smallestValue, smallestIndex, tempValue
For c = 0 To uBound( arToSort, 2 ) - 1
smallestValue = arToSort( sortBy, c ) smallestIndex = c
For d = c + 1 To uBound( arToSort, 2 ) if not compareDates then if strComp( arToSort( sortBy, d ), smallestValue ) < 0 Then smallestValue = arToSort( sortBy, d ) smallestIndex = d End if
else if not isDate( smallestValue ) then arraySort = arraySort( arToSort, sortBy, false) exit function
else if dateDiff( "d", arToSort( sortBy, d ), smallestValue ) > 0 Then smallestValue = arToSort( sortBy, d ) smallestIndex = d End if
end if
end if
Next
if smallestIndex <> c Then 'swap For e = 0 To uBound( arToSort, 1 ) tempValue = arToSort( e, smallestIndex ) arToSort( e, smallestIndex ) = arToSort( e, c ) arToSort( e, c ) = tempValue Next End if