Click here to Skip to main content
Click here to Skip to main content
Go to top

ObjectComparer

, 10 Feb 2003
Rate this:
Please Sign up or sign in to vote.
Sorting arrays of objects on arbitrary fields

Sample Image - shot.jpg

Introduction

Sooner or later, you will have an array of objects you'd like to sort. Unlike simple types like strings or integers, your objects usually have several properties you or your user want to sort on.

This article explains how to write a simple class which works with Array.Sort() to sort arrays of objects on dinamically selected fields. It's very similar to what DataView.Sort does for DataTables.

Background

Back in the old C times, when you wanted to use the standard sort or search functions you had to write a function to compare two objects of the desired type. The function received pointers to the objects, and returned -1, 0 or 1 when the first value was smaller, equal or bigger than the second.

You will then pass your function to the C sort function, using a function pointer (something similar to .NET's delegates).

This dirty but efficient technique allowed to create a single array sort function, that worked with any type of objects you wrote a comparer for.

Thinking in objects

In .NET, the approach to this problem is very similar. The Array.Sort method uses an IComparer with a method called Compare, that receives two objects and returns exactly the same as our old C comparer.

The class

The criteria to sort an array of objects is usually formed by the name of the fields, and an indication of ascending or descending order (like an SQL "ORDER BY" clause).

So, the constructor of our class accepts exactly those parameters:

public ObjectComparer(string[] fields, bool[] descending)
{
    Fields = fields;
    Descending = descending;
}

To make it easier to use, I also implemented a constructor for "all ascending" fields:

public ObjectComparer(params string[] fields) : this(fields, new bool[fields.Length]) {}

The alternate constructor just calls the first one with an array of false booleans for the descending parameter. Remember that, since bools are structs, they are initialized to 0 (false) on array creation.

Now, the method that does all the work

public int Compare(object x, object y)
{
    //Get types of the objects
    Type typex = x.GetType();
    Type typey = y.GetType();

    for(int i = 0; i<Fields.Length; i++)
    {
        //Get each property by name
        PropertyInfo pix = typex.GetProperty(Fields[i]);
        PropertyInfo piy = typey.GetProperty(Fields[i]);

        //Get the value of the property for each object
        IComparable pvalx = (IComparable)pix.GetValue(x, null);
        object pvaly = piy.GetValue(y, null);

        //Compare values, using IComparable interface of the property's type
        int iResult = pvalx.CompareTo(pvaly);
        if (iResult != 0)
        {
            //Return if not equal
            if (Descending[i])
            {
                //Invert order
                return -iResult;
            }
            else
            {
                return iResult;
            }
        }
    }
    //Objects have the same sort order
    return 0;
}

Note that I don't implement ANY error-checking code. It's such a simple class that it's not worth it. Be sure to call it with correct parameters (existing properties, and two same-size parameter arrays).

Comparing apples and bananas?

The key here, is that the two objects don't have to be the same type, as long as they implement the same property, and the property is a type that implements IComparable. So, you could sort Controls based on their TabIndex, since it's an Int32.

Using the code

First build the ObjectComparer library, and then open the PersonSort project.

This sample project implements a simple class, Person, which represents a person with a Name (string) and an Age (int). We first create an array of persons:

Person[] personArray = new Person[]
{
    new Person("Joey", 21),
    new Person("Johnny", 30),
    new Person("Marky", 28),
    new Person("C.J.", 28),
    new Person("Joey", 25),
    new Person("Dee Dee", 33)
};

And then we can sort in any field we want:

//Sort by Age
Array.Sort(personArray, new ObjectComparer("Age"));
//Sort by Name, Age
Array.Sort(personArray, new ObjectComparer("Name", "Age"));
//Sort by Name, Age DESC
Array.Sort(personArray, new ObjectComparer(
    new string[]{"Name","Age"},
    new bool[]{false,true}
    ));

Conclusion

ObjectComparer is a nice tool for sorting arrays of objects on programmer or user request.

Whenever you create this kind of utility class, it's important to create good constructors, so they can be created and used in just one line.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here

Share

About the Author

Diego Mijelshon
Web Developer
United States United States
No Biography provided

Comments and Discussions

 
NewsExtension for generics Pinmemberdeecke28-Dec-05 0:07 
GeneralQuestion for ANYONE Pinmemberkopykake4-Dec-05 11:16 
GeneralRe: Question for ANYONE Pinmemberkopykake4-Dec-05 11:24 
GeneralGreat Article Pinmemberalam_pune9-Nov-05 11:24 
GeneralMulti-Property, Multi-Directional Pinmembercoar16-Aug-05 13:29 
GeneralGreat one; check for nulls PinsussAnonymous26-Oct-04 10:15 
GeneralRe: CORRECTION: check for nulls Pinmembercpy26-Oct-04 11:49 
GeneralVersion for both Fields &amp; Properties PinmemberOskar Austegard22-Mar-04 12:18 
GeneralOutstanding PinmemberSimon Segal9-Dec-03 18:19 
GeneralWorks like a charm... Pinsussjonx1-Dec-03 15:08 
QuestionWhat about the perf? PinmemberQuentin Pouplard16-Apr-03 3:57 
AnswerRe: What about the perf? Pinmembermordejai16-Apr-03 4:35 
GeneralMisnomer PinsussSimon Trew18-Feb-03 22:54 
GeneralRe: Misnomer Pinmembermordejai24-Feb-03 1:27 
GeneralRe: Mordejai Pinsussazusakt16-Jun-03 18:22 
GeneralRe: Mordejai Pinmembermordejai17-Jun-03 7:24 
GeneralExcellent PinmemberMarc Clifton12-Feb-03 1:34 
GeneralRe: Excellent Pinmembermordejai12-Feb-03 1:44 
GeneralRe: Excellent PinmemberMarc Clifton12-Feb-03 1:49 
GeneralRe: Excellent PinmemberNoah Duke12-Feb-03 5:04 
GeneralRe: Excellent Pinmembermordejai12-Feb-03 6:19 
GeneralGreat PinmemberSteve McLenithan11-Feb-03 11:14 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Mobile
Web01 | 2.8.140916.1 | Last Updated 11 Feb 2003
Article Copyright 2003 by Diego Mijelshon
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid