参考资料
本文内容自定义类Array.Sort参考资料System.Array.Sort 有很多对集合的操作,比如排序,查找,克隆等等,你可以利用这个类加深对IComparer、IComparable以及泛型委托、匿名方法、Lambda 表达式的理解。
下载 Demo自定义类自定义两个类:Person和PersonComparer。后面会用到这两个类。
自定义Person类Person类有两个属性:FirstName和LastName,重构了ToString方法。该类还继承IComparable接口,实现了CompareTo方法,会在后面Array.Sort方法中用到。如下所示:
publicclassPerson : IComparable
{
publicPerson()
{
}
publicPerson(stringfirstname,stringlastname)
{
this.FirstName = firstname;
this.LastName = lastname;
}
publicstringFirstName { get; set; }
publicstringLastName { get; set; }
publicoverridestringToString()
{
returnstring.Format("{0} {1}", FirstName, LastName);
}
publicintCompareTo(objectobj)
{
Person other = objasPerson;
returnthis.LastName.CompareTo(other.LastName);
}
}
说明:CompareTo方法,它提供了默认比较,按LastName升序排序。
自定义PersonComparer 类该类内部定义了一个比较类型,可以按FirstName或LastName比较,并且都是升序排序。PersonComparer类同时继承IComparer接口的非泛型形式和泛型形式,实现了它们相应的Compare方法,该方法会在Array.Sort中用到。如下所示:
publicclassPersonComparer : IComparer, IComparer<Person>
{
publicenumPersonCompareType
{
FirstName,
LastName
}
PRivatePersonCompareType compareType;
publicPersonComparer(PersonCompareType compareType)
{
this.compareType = compareType;
}
publicintCompare(objectx,objecty)
{
Person p1 = xasPerson;
Person p2 = yasPerson;
switch(compareType)
{
casePersonCompareType.FirstName:
returnp1.FirstName.CompareTo(p2.FirstName);
casePersonCompareType.LastName:
returnp1.LastName.CompareTo(p2.LastName);
default:
thrownewArgumentException("unexpected compare type");
}
}
publicintCompare(Person x, Person y)
{
Person p1 = x;
Person p2 = y;
switch(compareType)
{
casePersonCompareType.FirstName:
returnp1.FirstName.CompareTo(p2.FirstName);
casePersonCompareType.LastName:
returnp1.LastName.CompareTo(p2.LastName);
default:
thrownewArgumentException("unexpected compare type");
}
}
}
Array.SortArray.Sort 有 17 个“重载”,如下所示:
Sort(Array)
Sort(Array, Array)
Sort(Array, IComparer)
Sort(Array, Array, IComparer)
Sort(Array, Int32, Int32)
Sort(Array, Array, Int32, Int32)
Sort(Array, Int32, Int32, IComparer)
Sort(Array, Array, Int32, Int32, IComparer)
Sort<T>(T[])
Sort<T>(T[], IComparer<T>)
Sort<T>(T[], Comparison<T>)
Sort<T>(T[], Int32, Int32)
Sort<T>(T[], Int32, Int32, IComparer<T>)
Sort<TKey, TValue>(TKey[], TValue[])
Sort<TKey, TValue>(TKey[], TValue[], IComparer<TKey>)
Sort<TKey, TValue>(TKey[], TValue[], Int32, Int32)
Sort<TKey, TValue>(TKey[], TValue[], Int32, Int32, IComparer<TKey>)
从它们的参数,你可以先想象一下:
这些方法可以分成非泛型形式和泛型形式,也就是每个非泛型形式基本都会对应一个泛型形式;如果我们要对一个集合排序,肯定是要比较的,并且默认排序,一般是升序,当然也可以是降序;如果集合是字符串,那很好办,几乎不需要做什么;可如果集合是对象,那我们就必须指定两个对象之间如何比较;如果有两个集合,一个集合是当键,另一个集合是当值,用键为值排序,这当然也是可以的,比如Sort<TKey, TValue>;针对不同的场景,可以指定不同的比较方式,比如,参数中带ICompare的。可以指定按 LastName 升序或降序,或 FirstName 升序或降序 。如果集合仅仅是字符串数组,那很好办,如下代码所示,按升序排序:
string[] names = {"Emerson Fittipaldi","Niki Lauda","Ayrton Senna","Michael Schumacher"};
Array.Sort(names);
但外国人的姓在后面,要按我们的习惯如何按姓排序?字符串数组肯定不行,这就需要自定义的Person类了,假设有如下Person数组:
Person[] persons = {
newPerson("Emerson","Fittipaldi"),
newPerson("Niki","Lauda"),
newPerson("Ayrton","Senna"),
newPerson("Michael","Schumacher")
};
采用Sort(Array)这个方法,按姓的升序排序,如下代码所示:
Array.Sort(persons);
因为定义Person类时,继承了IComparer接口,并实现了CompareTo方法,里面规定了按姓LastName比较,并且是升序,所以Array.Sort方法就知道如何排序了。
如果有时需要按FirstName排序,有时用LastName,怎么办?这就需要自定义的类PersonComparer。采用Sort(Array, IComparer)这个方法,代码如下所示:
Array.Sort(persons,newPersonComparer(PersonComparer.PersonCompareType.FirstName));
Console.WriteLine("Sort By First Name:");
foreach(Person pinpersons)
{
Console.WriteLine(" "+ p);
}
Array.Sort(persons,newPersonComparer(PersonComparer.PersonCompareType.LastName));
Console.WriteLine("Sort By Last Name:");
foreach(Person pinpersons)
{
Console.WriteLine(" "+ p);
}
结果:
Sort By First Name:
Ayrton Senna
Emerson Fittipaldi
Michael Schumacher
Niki Lauda
Sort By Last Name:
Emerson Fittipaldi
Niki Lauda
Michael Schumacher
Ayrton Senna
如果我们事先未定义PersonComparer类,也没问题,可以采用Sort<T>(T[], Comparison<T>)这个方法,参数Comparison<T>是 .Net 提供的泛型委托,这意味着我们可以用匿名方法或 Lambda 表达式来规定Person如何比较,采用匿名方法如下所示:
Array.Sort(persons,
delegate(Person p1, Person p2)
{
returnp1.FirstName.CompareTo(p2.FirstName);
});
Array.Sort(persons,
delegate(Person p1, Person p2)
{
returnp1.LastName.CompareTo(p2.LastName);
});
或采用 Lambda 表达式形式:
Array.Sort(persons, (p1, p2) => p1.FirstName.CompareTo(p2.FirstName));
Array.Sort(persons, (p1, p2) => p1.LastName.CompareTo(p2.LastName));
如果有两个集合,让其中一个集合为另一个集合排序呢?若有两个Person集合,一模一样,只是一个当键,另一个当值,用键为值排序,如下代码所示:
Person[] personKeys = {
newPerson("Emerson","Fittipaldi"),
newPerson("Niki","Lauda"),
newPerson("Ayrton","Senna"),
newPerson("Michael","Schumacher")
};
Person[] personValues = {
newPerson("Emerson","Fittipaldi"),
newPerson("Niki","Lauda"),
newPerson("Ayrton","Senna"),
newPerson("Michael","Schumacher")
};
Array.Sort<Person, Person>(personKeys, personValues);
Array.Sort<Person, Person>(personKeys, personValues,newPersonComparer(PersonComparer.PersonCompareType.FirstName));
其中,
Sort有两个参数的泛型方法,personValues会按personKeys的LastName按升序排序。这是默认的;Sort有三个参数的泛型方法,personValues会按personKeys的FirstName按升序排序。
Array中的其他方法,像BinarySearch、Find相关和indexOf相关,跟Sort用法类似,因为它们的参数大都是IComparer、IComparable以及泛型委托。
参考资料.NET Framework System.Array
下载 Demo