IComparer, Compare, CompareTo for multiple comparisons for Sort inArray and List

R

raylopez99

This is an example of using multiple comparison criteria for IComparer/
Compare/CompareTo for List<> and Array.

Adapted from David Hayden's tutorial found on the net, but he used
ArrayList so the format was different.

Basically you can sort a class having members LastName (string),
FirstName (string) and Age (int) according to whether you want to sort
by Last Name, First Name or Age, using the .Sort function

Question for the group: a suggestion in Albahari C#3 in a Nutshell
says you can, as an alternative to calling Sort, use LINQ's "OrderBy"
and "ThenBy" operators. Unlike Array.Sort or List.Sort, the LINQ
operators don't alter the original array or list, but instead emit the
sorted result in a fresh IEnumerable<T> sequence.

Any idea on how this can be done here? Remember, the
"strings" (LastName, FirstName) and "int" (Age) are stored inside a
class here, so it might be hard to do, since it seems to me LINQ
queries require something like string [] FirstName = {"Tom", "Dick",
"Harry"}; outside a class, rather than having the variables inside a
class as here.

If there's an easy way to use Linq, please post the complete code
otherwise just a hint or pseudocode.

Thanks

RL


// September 30, 2008
//adapted from David Hayden [MVP C#] tutorial on net
// in Hayden an ArrayList rather than a List was used
// so the format was slightly different than here

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace console1
{
class Program
{
static void Main(string[] args)
{

List<Person> PersonList = new List<Person>();
PersonList.Add(new Person("ray", "lopez", 38));
PersonList.Add(new Person("zoe", "smith", 28));
PersonList.Add(new Person("nue", "mather", 58));

PersonComparer myPersonComparer = new PersonComparer();

myPersonComparer.ComparisonMethod =
PersonComparer.ComparisonType.Age;
PersonList.Sort(myPersonComparer);
foreach (Person p in PersonList) Console.Write(p.LastName
+ "|");
// works, sort by age

Console.WriteLine("");
myPersonComparer.ComparisonMethod =
PersonComparer.ComparisonType.LastName;
PersonList.Sort(myPersonComparer);
foreach (Person p in PersonList) Console.Write(p.LastName
+ "|");
//works, sort by last name

Console.WriteLine("");
myPersonComparer.ComparisonMethod =
PersonComparer.ComparisonType.FirstName;
PersonList.Sort(myPersonComparer);
foreach (Person p in PersonList) Console.Write(p.LastName
+ "|");
// works, sort by first name

// IComparer works for Array too

Person[] personArray = new Person[]{new Person("ray",
"lopez", 38), new Person("zoe", "smith", 28),new Person("nue",
"mather", 58)};
Array.Sort(personArray, myPersonComparer);
foreach (Person p in personArray) Console.Write(p.LastName
+ "!");
Console.WriteLine("");
myPersonComparer.ComparisonMethod =
PersonComparer.ComparisonType.Age;
Array.Sort(personArray, myPersonComparer);
foreach (Person p in personArray) Console.Write(p.LastName
+ "!!");
Console.WriteLine("\n");
}
}
}
///////////////////////////
/*
* smith|lopez|mather| //<--List is sorted by Age
lopez|mather|smith| //<--Sorted by Last Name
mather|lopez|smith| //<--Sorted by First name
mather!lopez!smith! //<--now for an array, rather than
list, also works, sort by FirstName
smith!!lopez!!mather!! <--sort array by age
Press any key to continue . . .
* */
////////////////////////////////////////////
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics;

namespace console1
{
class Person
{
public string LastName;
public int Age;
public string FirstName;

public Person(string fn, string ln, int age)
{
LastName = ln;
FirstName = fn;
Age = age;
}

public int CompareTo(Person p2, PersonComparer.ComparisonType
myCType)
{
switch (myCType)
{
case PersonComparer.ComparisonType.Age:
return Age.CompareTo(p2.Age);
case PersonComparer.ComparisonType.LastName:
return LastName.CompareTo(p2.LastName);
default:
return FirstName.CompareTo(p2.FirstName);
}
}

}

class PersonComparer : IComparer<Person>
{
public enum ComparisonType
{ FirstName = 1, LastName = 2, Age = 3 }
private ComparisonType _comparisonType;
public ComparisonType ComparisonMethod
{
get { return _comparisonType; }
set { _comparisonType = value; }
}

public int Compare(Person x, Person y)
{
Person p1;
Person p2;
if (x is Person) p1 = x as Person;
else
throw new ArgumentException("Object not type Person");
if (y is Person) p2 = y as Person;
else
throw new ArgumentException("Object not type Person");
return p1.CompareTo(p2,_comparisonType);

}
} } ////////////////////
 
F

Family Tree Mike

There is no requirement that the query results be of strings. I think the
following example addresses what you are asking, but if not, please clarify.
It orders the people by age, then lastname, then firstname.

var ages = from p in PersonList orderby p.Age, p.LastName, p.FirstName
select p;
foreach (Person p in ages)
Console.Out.WriteLine(p.LastName + " " + p.FirstName + " " + p.Age);
Console.In.ReadLine();
 
R

raylopez99

 I think the
following example addresses what you are asking, but if not, please clarify.
It orders the people by age, then lastname, then firstname.

Yes, it worked. That was deceptively easy; it makes me wonder why
even bother with IComparer, unless you want a permanent newly sorted
array or list.

Thanks, FTM, you're a real programmer.

RL
 
F

Family Tree Mike

There is still good reason to impliment IComparer etc for a library class
intended for use in other systems. After all, the other system developer may
not know LINQ, or just may choose other mechanisms. But in a single
developer environment, you may be right.
 

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