IComparable接口和IComparer接口
为了能够对数据项进行排序,就要确定两个数据项在列表中的相对位置,也就是要确定两个对象的“大小”关系。一般来说有如下两种方式来定义大小关系:
第一种方式是针对对象本身。为了使对象自己能够执行比较操作,该对象必须实现IComparable
接口,即至少具有一个CompareTo()
成员。
System.IComparable
接口中有一个方法,如下:
int CompareTo(object obj);
它根据当前对象与要比较的对象的“大小”来返回一个正数、0或一个负数。
所有的简单值类型(如int
,double
,decimal
等)、枚举和字符串类,都实现该接口;用户定义的任何类型,只要类型值是有序的,都可以实现该接口。
第二种方式是提供一个外部比较器。为了能够比较对象的大小,可以提供一个比较器,比较器实现了ICompare
接口。
System.Collections.IComparer
接口中有一个方法,如下:
int Compare(object obj1, object obj2);
它根据第一个对象与第二个对象的“大小”来返回一个正数、0或一个负数。例如:
int Compare(object obj1, object obj2){
return (abj1 as Book).price - (obj2 as Book).price;
}
上面这段代码表示按照书的价格的大小顺序升序排序。其中小于0的值表示第1的对象“小于”第2个对象,等于0表示两个对象“大小相等”,正数则表示第1个对象“大于”第2个对象。
使用Array类进行排序和查找
System.Array
类是用于对数组进行排序和搜索的类。Array
类提供了Sort()
和BinarySearch()
,可用于排序及查找,另外,还提供了Reverse()
方法进行反序。
1.Array.Sort()及Reverse
Array.Sort()
方法可以实现对一维数组的排序。常用的有以下几种形式:
public static void Sort(Array); // 对数组元素排序, 每个元素要求实现IComparable
public static void Sort(Array keys, Array values); // 根据keys数组对values排序
public static void Sort(Array, IComparer); // 对数组排序, 使用外部比较器
public static void Sort(Array keys, Array values, IComparer); // 根据keys数组对values排序, 排序时, 使用外部比较器
Array.Reverse()
方法,可以用来对整个数组顺序进行反转:
public static void Reverse(Array); // 对数组排序, 每个元素要求实现IComparable
2.Array.Sort()的泛型方法
Array.Sort()
方法还有一个泛型方法,Sort<T>(T[])
。它还可以带IComparer<T>
参数,除此外,还可以带一个Comparsiom委托,该委托的原型是:
public delegate int Comparsion<in T>(T x, T y);
写委托参数的简便方法是使用Lambda表达式,例如:
Array.Sort<Person>(people, (p1, p2) => p1.Age - p2.Age);
表示对人的数组按年龄从小到大排序。
3.Array.BinarySearch()
Array.BinarySearch()
方法可以实现在已经排序的一堆数组中进行元素查找,常用的有以下几种形式:
public static int BinarySearch(Array, object); // 在数组中进行查找对象object
public static int BinarySearch(Array, object, IComparer); // 使用外部比较器
使用BinarySearch()
要注意:在执行BinarySearch()之前必须先对数组进行排序。
示例:
using System;
public class Test
{
public static void Main(string[] args){
string[] ary = {
"Apple", "Pearl", "Banana", "Carrot" };
Show(ary);
Array.Sort(ary);
Show(ary);
int it = Array.BinarySearch(ary, "Pearl");
Console.WriteLine(it);
Array.Reverse(ary);
Show(ary);
}
public static void Show(object[] ary){
foreach (object obj in ary)
Console.Write(obj + " ");
Console.WriteLine();
}
}
运行结果:
集合类中的排序和查找
集合类中也有一些机制进行排序和查找,例如:
- ① 许多类中有
Contains()
方法进行查找。 - ② 许多类中的
ToArray()
方法,可以将它转成数组,再进行排序及查找。 - ③ 可以从其他集合构造一个新的ArrayList及SortedList对象,再进行排序及查找。
1.ArrayList的Sort( )及BinarySearch( )
ArrayList
中的方法有关排序及查找,常见的有:
public virtual void Sort();
public virtual void Sort(IComparer);
public virtual int BinarySearch(object);
public virtual int BinarySearch(object, IComparer);
对于一个集合类,可以构造一个ArrayList
实例:
public ArrayList(ICollection);
这个构造方法中,将一个集合类的对象进行复制,并生成一个ArrayList
类。
ArrayList
还提供Adapter()
方法,可以将其他IList
对象包含在ArrayList
中。
public static ArrayList Adapter(IList);
Adapter
不复制IList
的内容,它只为IList
创建ArrayList
包装;因此,对IList
进行更改也会影响ArrayList
。可以用此方法来使用ArrayList
类提供一般的Reverse
、BinarySearch
和Sort
方法。但是,通过此包装执行这些一般操作比直接在IList上应用这些操作效率要低。
2.SortedList
SortedList
类的对象,在加入元素时,就会自动排序。
可以通过创建一个SortedList
实例,来将一个IDictionary
对象(包括SortedList
对象)进行元素的复制,并且进行排序。
public class Test
{
static void Main(string[] args) {
Person[] Persons = {
new Person("Liu", true, 21),
new Person("Zhang", true, 18),
new Person("Tang", false, 23),
new Person("Lu", false, 21)
};
Random rnd = new Random();
SortedList list1 = new SortedList();
foreach (Person r in Persons)
list1.Add(r.ToString(), "Room:" + rnd.Next(1000));
Person.PrintKeysAndValues(list1);
SortedList list2 = new SortedList(list1, new MyComparer());
Console.WriteLine("111111111111111");
Person.PrintKeysAndValues(list2);
}
}
public struct Person : IComparable
{
public string Name;
public bool Sex;
public int Age;
public Person(string name, bool sex, int age) {
this.Name = name;
this.Sex = sex;
this.Age = age;
}
public int CompareTo(object obj) {
if (!(obj is Person))
throw new System.ArgumentException();
Person rec = (Person)obj;
if (this.Age > rec.Age) return 1;
else if (this.Age == rec.Age) return 0;
return -1;
}
public override string ToString() {
return "Name: " + Name + "; Sex: " + Sex + "; Age: " + Age;
}
public static void PrintKeysAndValues(SortedList myList) {
IDictionaryEnumerator myEnumerator = myList.GetEnumerator();
while (myEnumerator.MoveNext())
Console.WriteLine("{0}:\t\t{1}", myEnumerator.Key, myEnumerator.Value);
Console.WriteLine();
}
}
public class MyComparer : IComparer
{
public int Compare(object obj1, object obj2) {
if (!(obj1 is Person) || !(obj2 is Person))
throw new System.ArgumentException();
Person rec1 = (Person)obj1;
Person rec2 = (Person)obj2;
return rec1.Name.ToLower().CompareTo(rec2.Name.ToLower());
}
}