Array类使用 Quicksort 算法对数组中的元素进行排序。 Sort() 方法需要数组中的元素实现 IComparable 接口。 因为简单类型 如 System.String 和 System.Int32 实现了 IComparable 接口, 所以可以对包含这些类型的元素排序。
我们看个栗子:
string[] names = {
"Zhang San",
"Li Si",
"Wang Er",
"Ma Zi"
};
Array.Sort( names ); // core
foreach( string name in names )
{
Console.WriteLine( name );
}
// 输出结果
Li Si
Ma Zi
Wang Er
Zhang San
在这个栗子中,数组名称包含 string 类型的元素, 这个数组可以排序。
如果对数组使用自定义类, 就必须实现 IComparable 接口。 这个接口只定义了一个方法 CompareTo(), 如果要比较的对象相等,该方法就返回0。 如果该实例应排在参数对象的前面,该方法就返回小于0的值。 如果该实例应排在参数对象的后面,该方法就返回大于 0 的值。
我写个例子,具体怎么应用,都在里面了:
public class Person : IComparable<Person>
{
// 看重点 CompareTo() 函数
public int CompareTo(Person other)
{
if (other == null) return 1;
if (this.Age == other.Age)
{
if (this.CreateTime > other.CreateTime) // 这里简易处理时间比较
return 1;
else return -1;
}
else if (this.Age > other.Age)
{
return -1;
}
else
{
return 1;
}
}
// 下面的代码可以忽略不看
public string Name { get; private set; }
public int Age { get; private set; }
public int CreateTime { get; private set; }
public Person(string name, int age, int createTime)
{
Name = name;
Age = age;
CreateTime = createTime;
}
}
写个调用方法测试一下:
Person[] personArr = {
new Person("张三",10, 5), // 入学时间我就简易下,用1-9的单个数字代替咯
new Person("李四",11, 3),
new Person("王二",9, 3),
new Person("麻子",12, 2),
new Person("赵六",11, 2),
};
Array.Sort( personArr );
foreach( Person person in personArr )
{
Console.WriteLine( "姓名:" + person.Name + ", 年龄:" + person.Age + " 入学时间:" + person.CreateTime );
}
// 输出结果
姓名:麻子, 年龄:12 入学时间:2
姓名:赵六, 年龄:11 入学时间:2
姓名:李四, 年龄:11 入学时间:3
姓名:张三, 年龄:10 入学时间:5
姓名:王二, 年龄:9 入学时间:3
上面的例子中, 我们希望年龄大的排前面,小的排后面。 这个是毋庸置疑的, 但是如果年龄相等了,我们又对入学时间做了一个比较, 当入学时间早则排前面, 否则就后面。
如果 Person对象的排序方式与上述不同, 或者不能修改在数组中用做元素的类, 就可以实现 IComparer 接口或者 IComparer<T>接口。 这个接口定义了方法 Compare()。 要比较的类必须实现这两个接口之一, IComparer 接口独立于要比较的类。 这就是 Compare() 方法定义了两个要比较的参数的原因。其返回值与 IComparable 接口的 CompareTo()方法类似。
下面写个实现 IComparer<T> 的例子:
public class Person // 注意这个类取消了 IComparable<T> 接口的实现
{
public string Name { get; private set; }
public int Age { get; private set; }
public int CreateTime { get; private set; }
public Person(string name, int age, int createTime)
{
Name = name;
Age = age;
CreateTime = createTime;
}
}
public class PersonComparer : IComparer<Person> // 注意这个类实现了IComparer<T> 接口
{
{
public int Compare(Person x, Person y)
{
if (x == null && y == null) return 0;
if (x == null) return 1;
if (y == null) return -1;
if (x.Age == y.Age)
{
if (x.CreateTime > y.CreateTime)
return 1;
else return -1;
}
else if (x.Age > y.Age)
{
return -1;
}
else
{
return 1;
}
}
}
下面写调用代码:
Person[] personArr = {
new Person("张三",10, 5), // 入学时间我就简易下,用1-9的单个数字代替咯
new Person("李四",11, 3),
new Person("王二",9, 3),
new Person("麻子",12, 2),
new Person("赵六",11, 2),
};
Array.Sort( personArr, new PersonComparer() ); // core look look 使劲 look
foreach( Person person in personArr )
{
Console.WriteLine( "姓名:" + person.Name + ", 年龄:" + person.Age + " 入学时间:" + person.CreateTime );
}
// 输出结果
姓名:麻子, 年龄:12 入学时间:2
姓名:赵六, 年龄:11 入学时间:2
姓名:李四, 年龄:11 入学时间:3
姓名:张三, 年龄:10 入学时间:5
姓名:王二, 年龄:9 入学时间:3
这个例子实现的功能和前面的例子是一样的, 只不过一个是 person类自己实现了比较接口, 而后者单独继承比较接口来实现具体的比较逻辑。
注意: Aray类还提供了 Sort 方法,它需要将一个委托作为参数。 这个参数可以传递给方法,从而比较两个对象, 而不需要依赖 IComparable 或 IComparer 接口。 (具体怎么使用要等以后讲到委托的时候)