Implementing IComparable in a custom class (sorting more than one way)

D

Dales

I have a custom class that provides information about training course
history (in-house IT training).

There are numerous course history entries for a student or group of
students, and they're each new'ed up as an objCourseHistory object and
stored in an arraylist.

(Hardcoding examples for illustration purposes, in reality this is
done in a loop and built from external data)

'*************************************
Dim alCourseHistory as New Arraylist
Dim o as New objCourseHistory
With o
o.Course = "Visual Basic .NET"
o.CourseID = 1
o.Series = "DTNET"
o.InstructorID = "12345678"
o.Status = "C"
o.Offering = 5
o.AddDate("01-17-2004")
o.AddDate("01-18-2004")
o.AddDate("01-19-2004")
End With
alCourseHistory.Add(o)
'*************************************

In order to allow this arraylist to be sorted, I have implemented
IComparable and have the following "CompareTo" function:

'*************************************
Class objCourseHistory
Implements IComparable
....
....
Public Function CompareTo(ByVal obj As Object) _
As Integer Implements System.IComparable.CompareTo
If CType(obj, objCourseHistory)._course > Me._course Then
Return -1
Else
Return 0
End If
End Function
'*************************************

This works fine and allows my arraylist of "objCourseHistory" objects
to be sorted on the "Course" value before I display them on the form
by simply doing an arraylist.Sort() where arraylist contains my
objects.

Is there a way to allow this arraylist of objects to be sorted on
DIFFERENT fields as well, or do I get to pick one only and one only?

I'd like to implement my own sorting by clicking header labels and
sorting the arraylist differently then rebuilding the form. I'd like
to take this approach as a datagrid bound to a custom arraylist of
objects doesn't sort and even if I could get it to sort it doesn't
have near the level of customization I need for how I want my data
laid out - so I scrapped the datagrid approach long ago.

If anyone knows how to allow the CompareTo function to sort more than
one way based on an additional parameter (maybe an enumeration value
passed in?), please let me know.

Thanks!
 
J

Jon Skeet [C# MVP]

Is there a way to allow this arraylist of objects to be sorted on
DIFFERENT fields as well, or do I get to pick one only and one only?

The best way of doing this is not to use IComparable, but to use
IComparer, where you implement the comparison in a separate class. You
can then sort the list of objects (which themselves needn't know
anything about comparison) by whatever criteria you wish to put in the
comparing class (the one which implements IComparer).
 
1

100

Hi Dales,
When you call ArrayList.Sort it has 3 overloads. 2 of them accept object
supporting IComparer interface.
That interface has only method Compare and it is responsible to compare two
objects and return result saying which is bigger or the elements are equal.
If you use those two overloads ArrayList will use IComparer to sort the
items rather than items' IComparable.CompareTo.

You can have as many comparator objects (implementing IComparer) interface
as different ways of sorting you want and call ArrayList.Sort(comparer)
providing the correct comparer.

HTH
B\rgds
100
 
J

Jason Daley

Jon,

Thanks for the prompt reply. In theory, I understand your reply, but
I've only been coding in VB.NET for a few months now and I'm not sure
how to implement what you've explained.

Is there a way you can show me a very simple example (I don't want to
ask too much of your time, but if I see an example, I can get it to
work) of how you would do that?

If you don't have time, I'll figure it out eventually.

Thanks,

Jason
 
J

Jon Skeet [C# MVP]

Jason Daley said:
Thanks for the prompt reply. In theory, I understand your reply, but
I've only been coding in VB.NET for a few months now and I'm not sure
how to implement what you've explained.

Is there a way you can show me a very simple example (I don't want to
ask too much of your time, but if I see an example, I can get it to
work) of how you would do that?

If you don't have time, I'll figure it out eventually.

Sure. This is in C#, but hopefully that won't be a problem for you.
Suppose you have a list of Employee objects, each of which has a name
and a department. You want to sort the list by each of these two
properties. The first class is just the Employee class. It's just a way
of storing a name and department, both of which are strings.

The next two classes are the implementations of IComparer: NameComparer
and DepartmentComparer. They're not very fully implemented - they
assume the type of object passed to them rather than throwing
ArgumentException appropriately, and they don't deal with nulls
properly. See the MSDN documentation for IComparer for more details of
that.

The fourth class is just the test - it populates a list, then sorts and
displays the list using each of the comparers.

What I don't show here is that you could have a single instance of an
IComparer implementation in which you then store the properties you
currently wish to sort on. At that stage you might as well just
implement IComparable in the main class in the same way though.



using System;
using System.Collections;

class Employee
{
string name;
string department;

public string Name
{
get { return name; }
}

public string Department
{
get { return department; }
}

public Employee (string name, string department)
{
this.name = name;
this.department = department;
}
}

class NameComparer : IComparer
{
public int Compare (object o1, object o2)
{
string name1 = ((Employee)o1).Name;
string name2 = ((Employee)o2).Name;

return name1.CompareTo(name2);
}
}

class DepartmentComparer : IComparer
{
public int Compare (object o1, object o2)
{
string department1 = ((Employee)o1).Department;
string department2 = ((Employee)o2).Department;

return department1.CompareTo(department2);
}
}

class Test
{
static void Main()
{
ArrayList list = new ArrayList();

list.Add (new Employee ("Skeet", "Engineering"));
list.Add (new Employee ("Jones", "Sales"));
list.Add (new Employee ("Bloggs", "Marketing"));

Console.WriteLine("Sorting by name:");
list.Sort(new NameComparer());
foreach (Employee emp in list)
{
Console.WriteLine ("{0,-10} {1}",
emp.Name, emp.Department);
}

Console.WriteLine();
Console.WriteLine("Sorting by department:");
list.Sort(new DepartmentComparer());
foreach (Employee emp in list)
{
Console.WriteLine ("{0,-10} {1}",
emp.Name, emp.Department);
}
}
}
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top