Introduction
The .NET Framework makes it a cinch for developers to sort arrays by including a static method in
the Array class called Sort(). In its simplest form the Sort()
method accepts a single input parameter - the one-dimensional array to sort - and sorts the array.
This implementation of the Sort() method works well when the contents in the array
implement the IComparable interface. (All of the primitive .NET types - Integer, Double,
String, etc. - implement the IComparable interface.)
But what if you have an array of items that do not implement the IComparable interface?
For example, in a previous article, Displaying the Files in a Directory
using a DataGrid, the DirectoryInfo's GetFiles() method was used to retrieve
an array of FileInfo instances. This array was then bound to a DataGrid. (See
this live demo to see the files from the /demos
directory displayed in a DataGrid.)
Imagine, though, that we wanted to sort the array of FileInfo instances before
binding it to the DataGrid. The FileInfo class does not implement IComparable,
so we can't just pass the array of FileInfos into the Array.Sort() method.
Furthermore, even if we could, this might sort the array by the file name, whereas we might want to
sort it by the file size.
Fortunately, the .NET Framework is flexible enough to allow for custom sorting of any object in an
array. In order to sort arrays whose elements do not implement IComparable, we must
create a class that implements IComparer, which specifies how the array should be sorted.
In this article we will first look at sorting arrays that contain elements that implement IComparable.
Then we will see how to create a class that implements IComparer so that we can sort arrays
that do not contain elements that implement IComparable. Finally, we will look at how
to enhance the live demo presented in Displaying the Files in a Directory
using a DataGrid to allow for displaying the files in a directory in a sortable DataGrid.
An Introduction to Interfaces
An interface is a concept common to object-oriented programming that, if applies to a particular
class, indicates that the class must contain a certain set of methods. That is, with an interface,
you specify a number of methods, including their name, their return type, and their input parameters.
The interface does not contain any code for the methods - rather, it just has the method's declaration
present. Then, when you indicate that a class implements the interface, this class must
contain, at minimum, the methods outlined in the interface, providing the body of these methods.
Think of an interface as a contract. When a class implements an interface, it is saying to the world,
"I promise to have the methods outlined in the interface definition." The benefit of classes implementing
an interface, is that other developers can create libraries that accept any class instance, so long
as it implements a given interface.
In addition to developers being able to create their own interfaces, the .NET Framework provides a
number of built-in interfaces that its classes use. In this article, we'll look at two interfaces,
IComparable and IComparer. When a class implements IComparable
the class is essentially saying to the world, "Given an instance of myself, this instance can compare
itself to another instance, indicating if its 'less than', 'greater than', or 'equal' to the other instance."
When a class implements the Comparer interface, the class is saying to the world, "I am a
class that can make comparisons about instances of another class." In this article we'll see how
both of these interfaces help make sorting arrays easy with .NET!
Sorting an Array Whose Elements Implement IComparable
Arrays that consist of elements that implement the IComparable interface can be sorted
using the Sort() method via the following syntax: Array.Sort(ArrayName).
Classes that implement the IComparable interface guarantee that they have a method named
CompareTo() that takes in a single parameter, an Object, and returns an Integer. The
Integer value indicates how the existing class instance and the object passed into it compare to
one another. A value of 0 indicates that they are equal, a value less than zero indicates that the
class instance is less than the passed in object, and a value greater than zero indicates that the class
instance is greater than the passed in object.
Behind the scenes, the Array.Sort(ArrayName) method performs a
QuickSort on the
elements in the array ArrayName, using the CompareTo() method to compare the
elements in the array to one another.
The primitive data types in the .NET Framework all implement the IComparable interface.
Therefore, if you have an array of this type, you can use the Array.Sort(ArrayName)
approach to sort an array of these types, as the following example and live demo
illustrate:
<script language="VB" runat="server">
Sub Page_Load(sender as Object, e as EventArgs)
Dim randNumbers(10) as Integer
Dim i as Integer
Dim rndNum as New Random()
For i = 0 to 10
randNumbers(i) = rndNum.Next(100)
Next i
' Display the random numbers
randNumDisplay.DataSource = randNumbers
randNumDisplay.DataBind()
' Sort the array
Array.Sort(randNumbers)
' Display the sorted array
orderedNumDisplay.DataSource = randNumbers
orderedNumDisplay.DataBind()
End Sub
</script>
<b>Unsorted List of Random Numbers</b><br />
<asp:DataGrid runat="server" id="randNumDisplay" ShowHeader="False" />
<p>
<b>Sorted List of Random Numbers</b><br />
<asp:DataGrid runat="server" id="orderedNumDisplay" ShowHeader="False" />
Sorting an Array Whose Elements Do Not Implement IComparable
In an earlier article of mine, Displaying the Files in a Directory
using a DataGrid, I looked at how to use the DataGrid to display a list of files from a directory.
The DirectoryInfo class's GetFiles() method was used to retrieve an array
of FileInfo instances that were then bound to a DataGrid (see this
live demo). After publishing this article, I received feedback from a number of users who
wondered how one could display the list of files in a DataGrid, and also allow for the DataGrid to
be sortable.
In order to create a sortable DataGrid, we first need to be able to sort the array of FileInfo
instances returned by the DirectoryInfo class's GetFiles() method. However,
the FileInfo class does not implement the IComparable interface, so therefore
it is not possible to use the Array.Sort(ArrayName) approach. Rather, we have to
create a new class, one that implements IComparer. This new class will have a single job:
given two FileInfo instances, the class should be able to compare the two, and return
an integer value indicating if the first FileInfo instance is less than, equal to, or
greater than the second.
Of course, what does it mean for a FileInfo instance to be "less than" another? Does it
mean that the first FileInfo instance's file name comes before the second's alphabetically?
Does it mean that the first FileInfo instance's file size is less than the second's?
Clearly, any of these interpretations is valid. Furthermore, since in displaying the files in a
DataGrid we are display their file name, file size, and last written date, it should be possible to
sort the FileInfo instances by their file name, file size, and last write date.
For the time being, imagine that we already have created a class that implements IComparer
and allows for sorting by the FileInfo's file name, size, or last written date. Once
we have this completed, we can sort the array of FileInfos by calling the Array.Sort()
method like so: Array.Sort(ArrayName, InstanceOfComparingClass). Here, the
InstanceOfComparingClass is an instance of the class that implements IComparer.
The main task ahead of us now is creating the class that can compare FileInfo instances.
We'll look at creating this class in Part 2.