## 数组排序方法的性能比较（3）：LINQ排序实现分析

2010-01-27 00:02  Jeffrey Zhao  阅读(15834)  评论(26编辑  收藏  举报

# LINQ排序接口的定义、使用及扩展

public static IOrderedEnumerable<TSource> OrderBy<TSource, TKey>(
this IEnumerable<TSource> source, Func<TSource, TKey> keySelector);

public static IOrderedEnumerable<TSource> OrderBy<TSource, TKey>(
this IEnumerable<TSource> source, Func<TSource, TKey> keySelector, IComparer<TKey> comparer);

public static IOrderedEnumerable<TSource> OrderByDescending<TSource, TKey>(
this IEnumerable<TSource> source, Func<TSource, TKey> keySelector);

public static IOrderedEnumerable<TSource> OrderByDescending<TSource, TKey>(
this IEnumerable<TSource> source, Func<TSource, TKey> keySelector, IComparer<TKey> comparer);

public static IOrderedEnumerable<TSource> OrderBy<TSource, TKey>(
this IEnumerable<TSource> source, Func<TSource, TKey> keySelector, bool decending)
{
return decending ?
source.OrderByDescending(keySelector) :
source.OrderBy(keySelector);
}

public static IOrderedEnumerable<TSource> OrderBy<TSource, TKey>(
this IEnumerable<TSource> source, Func<TSource, TKey> keySelector, Comparison<TKey> compare, bool decending)
{
return decending ?
source.OrderByDescending(keySelector, new FunctorComparer<TKey>(compare)) :
source.OrderBy(keySelector, new FunctorComparer<TKey>(compare));
}

employee.OrderBy(p => p.Manager, (m1, m2) => ... /* 比较逻辑 */, false);

intArray.OrderBy(i => i);

# OrderedEnumerable的实现

public static IOrderedEnumerable<TSource> OrderBy<TSource, TKey>(
this IEnumerable<TSource> source, Func<TSource, TKey> keySelector)
{
return new OrderedEnumerable<TSource, TKey>(source, keySelector, null, false);
}

OrderedEnumerable<TElement, TKey>的含义是“根据TKey排序TElement序列的结果”，它的构造函数仅仅是保留传入的参数：

internal OrderedEnumerable(
IEnumerable<TElement> source, Func<TElement, TKey> keySelector, IComparer<TKey> comparer, bool descending)
{
// 省略参数校验

base.source = source;
this.parent = null;
this.keySelector = keySelector;
this.comparer = (comparer != null) ? comparer : ((IComparer<TKey>) Comparer<TKey>.Default);
this.descending = descending;
}

internal abstract class OrderedEnumerable<TElement> : IEnumerable<TElement>...
{
internal IEnumerable<TElement> source;

internal abstract EnumerableSorter<TElement> GetEnumerableSorter(EnumerableSorter<TElement> next);

public IEnumerator<TElement> GetEnumerator()
{
var buffer = new Buffer<TElement>(this.source);
if (buffer.count <= 0) yield break;

var sorter = this.GetEnumerableSorter(null);
var map = sorter.Sort(buffer.items, buffer.count);

for (var i = 0; i < buffer.count; i++)
{
yield return buffer.items[map[i]];
}
}

...
}

# 排序实现：EnumerableSorter

LINQ排序的实现关键还是在于EnumerableSorter<TElement>，我们且看其Sort代码：

internal abstract class EnumerableSorter<TElement>
{
internal abstract int CompareKeys(int index1, int index2);
internal abstract void ComputeKeys(TElement[] elements, int count);

private void QuickSort(int[] map, int left, int right)
{
...
}

internal int[] Sort(TElement[] elements, int count)
{
this.ComputeKeys(elements, count);

int[] map = new int[count];
for (int i = 0; i < count; i++)
{
map[i] = i;
}

this.QuickSort(map, 0, count - 1);
return map;
}
}

var sorted = from p in people
orderby p.Age
orderby p.ID descending
select p;

# LINQ排序与Array.Sort<T>的性能比较

• Array.Sort<T>：使用IComparer<T>对象比较两个元素的大小。
• LINQ排序：首先根据keySelector获得TKey序列，然后在排序时使用IComparer<TKey>比较两个TKey元素的大小。

public class Person
{
public int Age { get; set; }
}

public class PersonComparer : IComparer<Person>
{
public int Compare(Person x, Person y)
{
return x.Age - y.Age;
}
}
Person[] people = ...

var byLinq = people.OrderBy(p => p.Age).ToList();
var byArray = Array.Sort(people, new PersonComparer());

• Array.Sort<T>：虽然不需要进行额外的元素复制，但是调用PersonComparer.Compare方法的开销较大——访问Age属性相当于调用get_Age方法（如果没有内联的话——不过从实际结果看的确被内联了）。
• LINQ排序：虽然需要进行额外的元素复制，而且需要事先计算出排序用的键值（Age属性），但是在排序时只需直接比较int即可，效率较高。