When you think ASP, think...
Recent Articles
All Articles
ASP.NET Articles
ASPFAQs.com
Message Board
Related Web Technologies
User Tips!
Coding Tips
Search

Sections:
Book Reviews
Sample Chapters
Commonly Asked Message Board Questions
JavaScript Tutorials
MSDN Communities Hub
Official Docs
Security
Stump the SQL Guru!
Web Hosts
XML
Information:
Advertise
Feedback
Author an Article
Jobs

ASP ASP.NET ASP FAQs Message Board Feedback ASP Jobs
 
Print this Page!
Published: Wednesday, June 4, 2003

Sorting An Array Using Array.Sort(), Part 2

By Scott Mitchell


  • Read Part 1

  • In Part 1 we looked at how to sort an array consisting of elements that implemented IComparable. This approach works great if you have an array of, say, primitive types, but what if you have an array of more complex objects that do not implement IComparable, like FileInfo instances? As we saw in Part 1, the solution is to create a custom class that implements IComparer, thusly providing the functionality needed to compare items of the complex object's type. In this part we'll build this class to compare two FileInfo objects.

    - continued -

    Building a Class That Implements IComparer


    The IComparer interface defines one method: Compare(obj1, obj2), where both obj1 and obj2 are objects. The method must return an Integer identifying if obj1 is less than, equal to, or greater than obj2. (As with the CompareTo() method of the IComparable interface, a return value less than zero indicates obj1 is less than obj2, a value of zero indicates that they are equal, and a positive value indicates that obj1 is greater than obj2.)

    So, any class that implements IComparer must also implement this Compare() method. Recall that the FileInfo class has a variety of properties that we might want to sort by, such as the file name, the file's size, the last written date, and others. Therefore, it would be wise to allow for our comparer class to sort by any of these properties. To make this a reality, let's start by creating an enumeration of all of the possible ways we want to allow the user to sort the data. This can be accomplished by adding the following code to your ASP.NET Web page's code-behind class file (outside of the class):

    Public Enum CompareByOptions
      FileName
      LastWriteTime
      Length
    End Enum
    

    Here we are have an enumeration with three members. Now, let's look at the code for the class to compare FileInfo objects. Let's name this class CompareFileInfoEntries. Add this class's code to the code-behind ASP.NET page as well, just like you did for the enumeration:

    Public Class CompareFileInfoEntries
      Implements IComparer
    
      Private compareBy As CompareByOptions = CompareByOptions.FileName
    
    
      Public Sub New(ByVal cBy As CompareByOptions)
        compareBy = cBy
      End Sub
    
      Public Overridable Overloads Function Compare(ByVal file1 As Object, _
             ByVal file2 As Object) As Integer Implements IComparer.Compare
        'Convert file1 and file2 to FileInfo entries
        Dim f1 As FileInfo = CType(file1, FileInfo)
        Dim f2 As FileInfo = CType(file2, FileInfo)
    
        'Compare the file names
        Select Case compareBy
          Case CompareByOptions.FileName
            Return String.Compare(f1.Name, f2.Name)
          Case CompareByOptions.LastWriteTime
            Return DateTime.Compare(f1.LastWriteTime, f2.LastWriteTime)
          Case CompareByOptions.Length
            Return f1.Length - f2.Length
        End Select
      End Function
    End Class
    

    Note that this class implements the IComparer interface. In VB.NET this is accomplished using the Implements keyword as shown above. In C#, you simply list the implemented interface(s) after the class's name, like: class CompareFileInfoEntries : IComparer. This class contains a single private member variable, compareBy, which specifies how the comparison should be performed. The class's constructor takes in a CompareByOptions enumeration value, specifying how the comparison should be made.

    In the Compare() method, the first thing that we do is cast the two input objects from objects to FileInfos. Next, we determine how we should be comparing the two FileInfo objects. If the compareBy member variable is set to CompareByOptions.FileName, we simply use the String class's Compare method to compare the Name of the two FileInfo objects. If its set to CompareByOptions.LastWriteTime, we use the DateTime class's Compare method to compare the LastWriteTime properties. Finally, if the compareBy member variable is set to CompareByOptions.Length, we return the difference of the two FileInfo's Length properties, since this will return a negative number if the first FileInfo's Length is less than the second's, 0 if they are equal, and a positive number if the first FileInfo's is greater than the second's.

    Putting It All Together


    Now that we have the CompareFileInfoEntries we can sort an array of FileInfo objects using the following syntax: Array.Sort(ArrayName, New CompareFileInfoEntries(HowToSort)), where HowToSort is a member from the CompareByOptions enumeration. For example, to sort the array by the FileInfos' Length properties, we'd use: Array.Sort(ArrayName, New CompareFileInfoEntries(CompareByOptions.Length)).

    We now want to convert our previous live demo into one that allows for sorting. To accomplish this we first need to configure the DataGrid for sorting, which entails setting the AllowSorting property to True and creating an event handler for the DataGrid's SortCommand event. In the SortCommand event, then, we need to determine what property the user wants to sort the DataGrid by, and then use the appropriate syntax for the Array.Sort() method. The complete code can be seen below; there's also an accompanying live demo.

    ListArticles.Sortable.aspx


    <%@ Page Language="vb" AutoEventWireup="false" 
        Codebehind="ListArticles.Sortable.aspx.vb" 
        Inherits="SortableFileEntries.ListArticleSortable"%>
    <form runat="server" ID="Form1">
       <asp:DataGrid runat="server" id="articleList" 
           Font-Name="Verdana" AutoGenerateColumns="False" 
           AlternatingItemStyle-BackColor="#eeeeee" HeaderStyle-BackColor="Navy" 
           HeaderStyle-ForeColor="White" HeaderStyle-Font-Size="15pt" 
           HeaderStyle-Font-Bold="True" 
           AllowSorting="True" OnSortCommand="sortDisplay">
        <Columns>
         <asp:HyperLinkColumn DataNavigateUrlField="Name" DataTextField="Name" 
                  HeaderText="File Name" SortExpression="FileName" />
         <asp:BoundColumn DataField="LastWriteTime" HeaderText="Last Write Time" 
                  ItemStyle-HorizontalAlign="Center" DataFormatString="{0:d}" 
                  SortExpression="LastWriteTime" />
         <asp:BoundColumn DataField="Length" HeaderText="File Size" 
                  ItemStyle-HorizontalAlign="Right" 
                  DataFormatString="{0:#,### bytes}" 
                  SortExpression="Length" />
        </Columns>
       </asp:DataGrid>
    </form>    
    		

    Code-Behind Class - ListArticles.Sortable.aspx


    Imports System.Collections
    Imports System.IO
    
    Public Class ListArticleSortable
      Inherits System.Web.UI.Page
      Protected WithEvents articleList As System.Web.UI.WebControls.DataGrid
    
    #Region " Web Form Designer Generated Code "
    
      'This call is required by the Web Form Designer.
      <System.Diagnostics.DebuggerStepThrough()> _
      Private Sub InitializeComponent()
    
      End Sub
    
      Private Sub Page_Init(ByVal sender As System.Object, _
                 ByVal e As System.EventArgs) _
                 Handles MyBase.Init
        'CODEGEN: This method call is required by the Web Form Designer
        'Do not modify it using the code editor.
        InitializeComponent()
      End Sub
    
    #End Region
    
      Private Sub Page_Load(ByVal sender As System.Object, _
              ByVal e As System.EventArgs) Handles MyBase.Load
        If Not Page.IsPostBack Then
          BindData(CompareByOptions.FileName)
        End If
      End Sub
    
      Private Sub BindData(ByVal compareMethod As CompareByOptions)
        Dim dirInfo As New DirectoryInfo(Server.MapPath(""))
        Dim fileInfoArray() As FileInfo = dirInfo.GetFiles("*.aspx")
    
        Array.Sort(fileInfoArray, New CompareFileInfoEntries(compareMethod))
        articleList.DataSource = fileInfoArray
        articleList.DataBind()
      End Sub
    
      Public Sub SortDisplay(ByVal sender As Object, ByVal e As _
                        DataGridSortCommandEventArgs)
        Select Case e.SortExpression
          Case "FileName"
            BindData(CompareByOptions.FileName)
          Case "LastWriteTime"
            BindData(CompareByOptions.LastWriteTime)
          Case "Length"
            BindData(CompareByOptions.Length)
        End Select
      End Sub
    End Class
    
    
    Public Enum CompareByOptions
      FileName
      LastWriteTime
      Length
    End Enum
    
    
    Public Class CompareFileInfoEntries
      Implements IComparer
    
      Private compareBy As CompareByOptions = CompareByOptions.FileName
    
    
      Public Sub New(ByVal cBy As CompareByOptions)
        compareBy = cBy
      End Sub
    
      Public Overridable Overloads Function Compare(ByVal file1 As _
             Object, ByVal file2 As Object) _
             As Integer Implements IComparer.Compare
        'Convert file1 and file2 to FileInfo entries
        Dim f1 As FileInfo = CType(file1, FileInfo)
        Dim f2 As FileInfo = CType(file2, FileInfo)
    
        'Compare the file names
        Select Case compareBy
          Case CompareByOptions.FileName
            Return String.Compare(f1.Name, f2.Name)
          Case CompareByOptions.LastWriteTime
            Return DateTime.Compare(f1.LastWriteTime, f2.LastWriteTime)
          Case CompareByOptions.Length
            Return f1.Length - f2.Length
        End Select
      End Function
    End Class
    
    [View a Live Demo!]

    Conclusion


    In this article we examined how to sort arrays. If the array's elements are of a type that implements the IComparable interface, then sorting the arrays is as simple as calling Array.Sort(ArrayName). For more complicated objects that do not implement the IComparable interface, we can create a class designed specifically to compare to of these objects. This class needs to implement the IComparer interface, thereby providing a Compare() method. With such a class, we can use the Array.Sort() method to sort an array by passing in both the array to sort and an instance of the compare class.

    After presenting the basics of sorting .NET arrays, we then turned to a real-world problem: sorting an array of FileInfo objects based on one of a variety of properties. Specifically, we saw how to "upgrade" an earlier demo that merely listed the files in a directory in a DataGrid, to one that listed the files in a directory in a sortable DataGrid.

    Happy Programming!

  • By Scott Mitchell



  • ASP.NET [1.x] [2.0] | ASPMessageboard.com | ASPFAQs.com | Advertise | Feedback | Author an Article