One thing I'm pretty sure of is that boys like to compare things. Yes, I know what you're thinking - that's not where I'm going here. I have a vivid recollection of a time a few years back when I tipped the scales at a good 20% more than I currently do. I remember shopping in a grocery store for some snacks with pals Brian Randell and Andy Baron. Andy (who is also svelter now than he was then) and I were both kvetching about the sizes of our, um, rears. I was sure that mine was larger but Andy wasn't convinced. Right there in the grocery store I coerced Brian to act as judge. (I've spared you the photo. I figured your imagination was creative enough in this particular scenario.) I won, of course. I've always won this contest. I believe I always will.

Flash forward a few years. It's PDC time in 2003, and a bunch of my geek pals are staying at my house in the hills of Los Angeles. Andy was there again, but for this event we added iron-man Australian Adam Cogan and "I've ridden my bike across the country" Oregonite Tom Howe. We had been biking up the hill my house is built upon (see the previous two issues of CoDe Magazine for more biking stories) and Adam had made his way up with nary a huff nor a puff, even though it's a steep ride. We figured he had to have the largest thighs in the group. So, again, we started measuring. This particular body part turns out to be harder to measure via mere visual inspection. What we needed was some algorithm for comparing the actual "thighage," so we could sort ourselves accordingly. Pragmatic Mary Chipman suggested that we use a measuring tape. Of course, I don't own one so we substituted dental floss. (Don't you wish you had been there?) Adam won this contest, although barely.

The segue to real content comes unusually early this month, because I have this feeling that I've described comparing body parts just about enough. Of course, comparing and sorting are a critical part of working with the .NET Framework. Actually, it's hard to imagine getting much computing work done without sorting and comparing, and I love the way the .NET Framework handles these tasks. Arrays, collection classes, and any other data structure in which you might want to put ordered data all provide a Sort method that takes care of the mundane sorting details. Unless you have some specific needs, you shouldn't need to create your own sorting procedure ever again. You may need to assist the .NET Framework in comparing and ordering your data, however.

If you've created a simple ArrayList instance, for example, and you add four items to it, you can easily sort and display the results. The following code demonstrates how this works:


Dim al As New ArrayList

al.Add("Ken")
al.Add("Tom")
al.Add("Andy")
al.Add("Adam")
al.Sort()
For Each name As String In al
  Debug.WriteLine(name)
Next


When you sort a collection of any type of object, the Sort method needs some way to compare any two instances of the type. In order to generalize this comparison behavior, the .NET Framework provides a default compare method for each type that it may need to sort. Calling the Sort method of the ArrayList class uses the default "comparer" for each element in the data structure in order to determine the correct ordering. Because each element is a string, and the String class provides a mechanism for comparing one string to another, this all works transparently. If you read the documentation for the String class (or any other simple class built into the .NET Framework) you'll find that the String class implements the IComparable interface, and by doing so, it provides a CompareTo method that implements the single required member of the IComparable interface.

If you read the documentation for the IComparable interface, you'll learn that this interface requires implementers to provide a method (normally named CompareTo) that accepts an object and returns an integer. The goal of this procedure is to compare the instance of the object whose CompareTo method you called with the object passed to the procedure. If the two objects have the same value (and it's up to the developer of the class to determine what the "value" of the object is), the procedure should return 0. If the current instance value is less than the passed-in object, the method will return a negative value; if greater, the method will return a positive value.

For built-in classes that implement IComparable, you don't have to do anything if you want to use the default sort order. But what if you want to sort instances of your own class? You can provide a default sort capability for your class by implementing the IComparable interface yourself. Say, for example, you've created a BigBoy class to track thigh size. If you want to be able to sort a collection of BigBoy objects, you'll need to implement IComparable. The following example includes code that allows you to compare two BigBoy instances, and thereby, sort a collection of these objects:


Public Class BigBoy
  Implements IComparable
  Public Name As String
  Public ThighSize As Integer

  Public Sub New( _
   ByVal Name As String, _
   ByVal Size As Integer)

    Me.Name = Name
    Me.ThighSize = Size
  End Sub

  Public Overrides Function ToString() _
   As String
    Return String.Format( _
      "{0} has {1} inch thighs.", _
      Me.Name, Me.ThighSize)
  End Function

  Function CompareTo( _
   ByVal obj As Object) As Integer _
   Implements IComparable.CompareTo
    Dim other As BigBoy
    other = CType(obj, BigBoy)
    Return Me.Name.CompareTo(other.Name)
  End Function
End Class


The CompareTo method in BigBoy, which compares two instances of the type, uses the CompareTo method of the String class in order to compare the two names. What if you wanted to sort on thigh size instead? No problem?just modify the line of code that performs the comparison:


Return Me.ThighSize. _
 CompareTo(other.ThighSize)


It doesn't really matter how you perform this comparison, as long as your return value matches the requirements of the CompareTo method.

You might also want to change the default sort behavior for a built-in type, or provide multiple sort orderings for your own class. For example, what if you want to sort a collection of strings in reverse order? What if you want to be able to provide your list of BigBoy objects in either name or size order, depending on the circumstances? In that case, you'll need to provide yet another class?this time you need to implement the IComparer interface.

The Sort method of each collection type allows you to pass an instance of a class that implements IComparer in order to determine the compare order for the objects within the collection. The IComparer interface requires you to supply just a single procedure?Compare?to compare two objects that it receives as parameters.

For example, to sort strings in reverse order, you might create a class that implements IComparer like this:


Class StringReverseComparer
  Implements IComparer

  Public Function Compare( _
    ByVal x As Object, _
    ByVal y As Object) As Integer _
    Implements System.Collections. _
    IComparer.Compare

    Dim str1 As String = _
     CType(x, String)
    Dim str2 As String = _
     CType(y, String)
    Return -1 * x.CompareTo(y)
  End Function
End Class


Then, when it comes time to sort the ArrayList of strings, you could revise the previous code so that it looks like this:


al.Sort(New StringReverseComparer())


The same concept applies to the BigBoy class. To create a comparison class that allows you to sort based on ThighSize, you could add this class to your project:


Class ThighComparer
  Implements IComparer

  Public Function Compare( _
    ByVal x As Object, _
    ByVal y As Object) As Integer _
    Implements System.Collections. _
    IComparer.Compare

    Dim bb1 As BigBoy = CType(x, BigBoy)
    Dim bb2 As BigBoy = CType(y, BigBoy)
    Return bb1.ThighSize. _
     CompareTo(bb2.ThighSize)
  End Function
End Class


Then, when it came time to sort the ArrayList, you could either sort using the default sort:


al.Sort()


or you could sort using the new comparer:


al.Sort(New ThighComparer())


I clearly like to compare things, and this is just a clean and elegant solution to a common and basic programming problem. This is just about as simple a solution as they could have come up with. Using the IComparable and IComparer interfaces, you can create flexible applications that can work with data in any number of ways. And one thing's for sure: it's more practical than comparing using dental floss.