![]() |
Platforms, Frameworks & Libraries »
.NET Framework »
General
Intermediate
License: The Code Project Open License (CPOL)
MultiList: .NET Generic List with Multiple Sort OrdersBy gogglinThe MultiList class extends the functionality of the generic list. The MultiList class manages multiple sort orders on lists. It is best suited to object lists where searching is required on more than one criteria. |
C# (C# 2.0), Windows, .NET (.NET 2.0), Dev
|
|
Advanced Search Add to IE Search |
|
|
|
||||||||||||||||
The MultiList class manages multiple sort orders on lists. It is best suited to object lists where searching for objects is required on more than one criteria. It is also suited when searches must be done on complete objects as well as properties within objects. The class employs a binary search algorithm to find objects in lists, as well as to insert objects in sorted order within lists.
This code sample demonstrates the declaration of a Person class, and the instantiation of a MultiList class to manage lists by three sort orders on the Person class. This documentation does not extensively demonstrate how to perform searches, additions, or deletions to the MultiList object; the reader should refer to the unit test code for this project for those examples. Here are some overview points about the MultiList class:
Remove method before the modification, then reinsert it with the Add method after the modification foreach ActiveList property can be set before enumeration, to indicate which sort order to apply to subsequent enumerations Add method adds an object to all managed lists Remove method removes an object from all managed lists The idea for this library came about as I was working on an unrelated project that manages a list on two different sort orders. Initially I used a list that was sorted on the most important sort order, and a clumsy property and filter which allowed iteration on the second sort order. I knew it was a total kludge, but it worked. Before beginning this library, I searched for this type of functionality in publicly available code, with no luck. It seems like a fairly common problem, easily encountered in routine scenarios:
The List<T> class in the System.Collections.Generic namespace provides all of the functionality to search and sort lists, but it comes up short in some ways:
FindLast and FindLastIndex methods. The MultiList library addresses all these issues.
This code example demonstrates the declaration of a Person class, and the instantiation of a MultiList class to manage lists by three sort orders on the Person class. This documentation does not extensively demonstrate how to perform searches, additions, or deletions to the MultiList object; the reader should refer to the unit test code of this project for those examples.
The Person class is defined as follows:
public class Person : System.IEquatable<Person>
{
public enum Profession
{
Teacher,
Nurse,
Barber,
Welder,
Carpenter,
Lawyer
};
private string _name;
private int _age;
private Profession _career;
private static int _static_sequence = 0;
private int _sequence;
public Person (string name, int age,
Profession career)
{
_name = name;
_age = age;
_career = career;
lock (typeof (Person))
{
_sequence = ++_static_sequence;
}
}
public string Name { get { return _name; } }
public int Age { get { return _age; } }
public Profession Career { get { return _career; } }
public int Sequence { get { return _sequence; } }
public bool Equals (Person p)
{
return Sequence == p.Sequence;
}
}
Note the following points about the Person class:
static sequence member and a sequence member at the object level to generate a unique ID. This ID is used to determine equality. The next step is to define an enumerator and three custom classes which are to be used as arguments to the MultiList constructor.
// declare the enumerator which defines the sort orders
// that we want on the Person class
private enum PersonSortCriteria
{
Name,
Age,
Career
};
public class NameComparer :
MultiList<Person>.ITypeComparer<string>,
IComparer<Person>
{
public int Compare (Person p1, Person p2)
{
return p1.Name.CompareTo (p2.Name);
}
public int Compare (Person p, string name)
{
return p.Name.CompareTo (name);
}
}
public class AgeComparer :
MultiList<Person>.ITypeComparer<int>,
IComparer<Person>
{
public int Compare (Person p1, Person p2)
{
return p1.Age - p2.Age;
}
public int Compare (Person p, int age)
{
return p.Age - age;
}
}
public class CareerComparer :
MultiList<Person>.ITypeComparer<Person.Profession>,
IComparer<Person>
{
public int Compare (Person p1, Person p2)
{
return p1.Career.CompareTo (p2.Career);
}
public int Compare (Person p, Person.Profession career)
{
return p.Career.CompareTo (career);
}
}
The last step is to instantiate the three comparer objects and the MultiList class object. Note that the comparer object argument order matches the order of the PersonSortCriteria enumerator constants in the constructor.
NameComparer nameComparer = new NameComparer ();
AgeComparer ageComparer = new AgeComparer ();
CareerComparer careerComparer = new CareerComparer ();
MultiList<Person> ml =
new MultiList<Person> (
typeof (PersonSortCriteria), nameComparer,
ageComparer, careerComparer);
After this, adding objects to the list is straightforward.
// add four Person objects to the MultiList
Person Jim = new Person ("Jim", 42,
Person.Profession.Teacher);
ml.Add (Jim);
ml.Add (new Person ("Susan", 29,
Person.Profession.Lawyer));
ml.Add (new Person ("Arthur", 22,
Person.Profession.Barber));
ml.Add (new Person ("Ellen", 29,
Person.Profession.Teacher));
A list can be searched for an index or for the actual object. It might be preferable to search for an index if you're not sure if a match will be found. If a match is not found, index searches return MultiList.NotFound. When a match is found, an index is returned that corresponds to the sort order of the search.
The following examples demonstrate the use of the index methods.
There are two types of searches that can be done on a MultiList object. The first type searches for an object with an existing Person object.
// return the index of Jim in the name sort list
int index = ml.FindIndex (PersonSortCriteria.Name, Jim);
// return the index of Jim in the age sort list
index = ml.FindIndex (PersonSortCriteria.Age, Jim);
The second type of search uses a data type that corresponds to a particular sort order.
// return the index of Susan in the name sort list
int index = ml.FindIndex<string>
(PersonSortCriteria.Name, nameComparer, "Susan");
// return the index of the first Person with an age of 29
index = ml.FindIndex<int>
(PersonSortCriteria.Age, ageComparer, 29);
// return the index of the first Person
// with a career of Barber
index = ml.FindIndex<Person.Profession>
(PersonSortCriteria.Career, careerComparer,
Person.Profession.Barber);
The ActiveList property may be used to specify a particular sort order, which will apply to all subsequent methods which do not specify a sort order.
ml.ActiveList = PersonSortCriteria.Age;
// return the index of the first Person with an age of 29
int index = ml.FindIndex<int>
(ageComparer, 29);
When an index is obtained, the object can be accessed in a couple of ways. In the previous code example, the ActiveList property was set to PersonSortCriteria.Age. If the Item indexer is used, it will return objects from the Age list.
// note that we first check to see that a valid index was
// returned, before accessing the list element.
if (index != MultiList.NotFound)
{
Person match = ml[index];
}
You may also access any of the lists using the GetObject method.
int index = ml.FindIndex<string>
(PersonSortCriteria.Name, nameComparer, "Susan");
if (index != MultiList.NotFound)
{
Person match = ml.GetObject (PersonSortCriteria.Name,
index);
}
The Find methods return a reference to the object stored in the list. When you use one of the Find methods that return an actual object, you will have to do so in a try/catch block, or else use the TryFind methods.
Person match;
try
{
match = ml.Find<string>
(PersonSortCriteria.Name, nameComparer, "Susan");
}
catch (MultiListObjectNotFoundException)
{
// not found
}
// set the active list to age, and use the
// TryFind method to search
ml.ActiveList = PersonSortCriteria.Age;
if (true == TryFind<string>
(ageComparer, 29, out match))
{
// a match was found
}
Several methods are available that return multiple objects or indexes when duplicates exist.
IndexRange range = ml.FindIndexes<int>
(PersonSortCriteria.Age, ageComparer, 29);
if (range.Count > 0)
{
// one or more matches was found
}
Person[] matches = ml.FindMultiple<int>
(PersonSortCriteria.Age, ageComparer, 29);
if (matches.Length > 0)
{
// one or more matches was found
}
The unit test code for this project requires NUnit 2.4.3.
IndexRange object and iteration. This object simplifies the handling of multiple indexes returned from Find methods. | You must Sign In to use this message board. | |||||||||||||||
|
|||||||||||||||
|
|||||||||||||||
|
|||||||||||||||
|
|||||||||||||||
General
News
Question
Answer
Joke
Rant
Admin
|
PermaLink |
Privacy |
Terms of Use
Last Updated: 1 Feb 2008 Editor: Sean Ewington |
Copyright 2008 by gogglin Everything else Copyright © CodeProject, 1999-2009 Web19 | Advertise on the Code Project |