Welcome

首页 / 软件开发 / 数据结构与算法 / 数组排序方法的性能比较(4):LINQ方式的Array排序

数组排序方法的性能比较(4):LINQ方式的Array排序2011-09-30 博客园 Jeffrey Zhao经过前两篇文章的分析,我们已经了解了Array.Sort<T>与LINQ排序两种实现方式的差别:前者 直接比较两个元素的大小,而后者先选出每个元素的“排序依据”再进行比较。因此,虽然后者需要相对 较多的“周边工作”,但由于每次比较时都可以仅仅使用高效的基础类型(如int),因此从整体来看, 两者的性能高低难以辨别。不过,既然我们已经了解LINQ排序“高效”的原因,又能否将其利用在数组排 序上呢?程序是人写的,此类问题大都有肯定的答案。那么我们现在就来实现一下。

API设计

关于这个问题,我设想过几种API使用与设计方式。例如,我起初想使用“标准”的扩展方法:

Person[] people = null;
people
.OrderBy(p => p.Age) // 指定主要排序规则
.OrderBy(p => p.ID, true /* decending */) // 指定次要排序规则
.Sort(); // 排序

在这样的API中,前两个OrderBy方法用于“收集排序条件”,而在最后的Sort方法中才对数组进行排 序。这个API在使用上问题不大,但是在实现上却有两个缺点。首先,对于数组来说,已经有定义在其上 的OrderBy方法,新的扩展方法与类库重名,难道要我换个名字嘛?我讨厌动这脑筋;其次,如果说第一 个OrderBy方法是定义在数组上的扩展方法,那么第二个OrderBy方法也是数组的扩展方法吗?

其实不然。既然我们要“收集”排序规则,因此必然需要使用一个对象进行保存——就叫做 OrderCriteria吧。那么第一个OrderBy方法便返回这样一个OrderCriteria对象,而第二个OrderBy则是定 义在OrderCriteria类上的。那么,我们是不是需要为数组和 OrderCriteria类各实现“一整套”的 OrderBy方法呢?这实在是一件麻烦的事情啊。

于是,我又想到了这样的接口:

new ArraySorter<Person>(people)
.OrderBy(p => Age)
.OrderBy(p => p.ID, true)
.Sort();

这样做的话,我们只要定义一个ArraySorter类型,再提供一套OrderBy方法即可。这种做法不仅仅是 省力,“统一”的排序入口还有另一个好处,因为我们可以实现这样的逻辑:

var sorter = new ArraySorter<Person>(people);

if (shouldOrderByAge)
{
sorter.OrderBy(p => p.Age);
}

if (shouldOrderById)
{
sorter.OrderBy(p => p.ID);
}

sorter.Sort();