How to Sort a Multi-Dimensional Array

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.

Introduction

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.

{mospagebreak title=A Quick Explanation of the Multi-Dimensional Array Function}

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:

arEvents(0, 0) = 1
arEvents(1, 0) = “01-12-2004″
arEvents(2, 0) = “Event #1″
arEvents(0, 0) = 2
arEvents(1, 0) = “10-16-2004″
arEvents(2, 0) = “Event #2″
arEvents(0, 0) = 3
arEvents(1, 0) = “02-13-2004″
arEvents(2, 0) = “Event #3″

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.

{mospagebreak title=And We Proceed with Our Checking}

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

Next
arraySort = arToSort
end function

{mospagebreak title=Conclusion}

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

Next

6 thoughts on “How to Sort a Multi-Dimensional Array

  1. Thank you for sharing your function, it has been very useful to me and saved me considerable time. I have a few comments:

    First of all, on the last page where you repeat all the code you have missed out the last two lines:

    arraySort = arToSort
    end function

    Secondly the function sorts in a case sensitive way, so that lowercase a-z is sorted before uppercase A-Z. It would be useful to add an extra parameter for case sensitive.

    Otherwise good job!

  2. Hi,

    Thanks for the great function.

    I have modified the script slightly by changing the compareDate to compareType.
    I needed to sort numbers.
    Here is the full modified funtion.

    ‘==============================================
    function arraySort( arToSort, sortBy, compareType )
    ‘==============================================

    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 compareType = “Text” then
    if strComp( arToSort( sortBy, d ), smallestValue ) < 0 Then
    smallestValue = arToSort( sortBy, d )
    smallestIndex = d
    End if

    elseif compareType = “Date” then
    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
    elseif compareType = “Number” then
    if cint( arToSort( sortBy, d ) ) < cint(smallestValue) Then
    smallestValue = arToSort( sortBy, d )
    smallestIndex = d
    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

    Next

    arraySort = arToSort
    end function

    ‘ Call function : NewCompleteArray = arraySort (CompleteArray, 1, “Number”)

  3. Thank you guys for this, great routine. Note you can sort decimal numbers by replacing cint with appropriate precision (clng, csng, cdbl) or using round function instead. :)

  4. Cleaned up the code abit.
    ‘==============================================
    function arraySort( arToSort, sortBy, compareType )
    ‘==============================================

    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 )
    select case compareType
    case “Text”
    if strComp( lcase(arToSort( sortBy, d )), lcase(smallestValue) ) < 0 Then
    smallestValue = arToSort( sortBy, d )
    smallestIndex = d
    end if

    case “Date”
    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

    case “Number”
    if cint( arToSort( sortBy, d ) ) < cint(smallestValue) Then
    smallestValue = arToSort( sortBy, d )
    smallestIndex = d
    End if
    End Select
    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

    Next

    arraySort = arToSort
    end function

  5. Something funny going on here:
    arEvents(0, 0) = 1
    arEvents(1, 0) = “01-12-2004″
    arEvents(2, 0) = “Event #1″
    arEvents(0, 0) = 2
    arEvents(1, 0) = “10-16-2004″
    arEvents(2, 0) = “Event #2″
    arEvents(0, 0) = 3
    arEvents(1, 0) = “02-13-2004″
    arEvents(2, 0) = “Event #3″

    (second dimension value not incrementing)

[gp-comments width="770" linklove="off" ]