自定义Lambda排序扩展 [英] Custom Lambda sort extension
问题描述
我想使用我的自定义扩展方法来订购对象列表.这只是一个样本,因此使用了冒泡排序.我目前的状态:
i want to use my custom extension method to order a list of objects. it's just a sample so it uses a bubblesort. my current state:
public static IOrderedQueryable<TSource> OrderByBubbleSort<TSource, TKey>(this IQueryable<TSource> source, Func<TSource, TKey> keySelector)
{
IComparer<TSource> comparer = Comparer<TSource>.Default;
List<TSource> Result = source.ToList();
for (int i = (source.Count() - 1); i >= 0; i--)
{
for (int j = 1; j <= i; j++)
{
if (comparer.Compare(Result[j - 1], Result[j]) > 0)
{
var temp = Result[j - 1];
Result[j - 1] = Result[j];
Result[j] = temp;
}
}
}
return (IOrderedQueryable<TSource>)Result;
}
所以我可以这样称呼:
List<Person> pList = ...
List<Person> Result = pList.OrderByBubbleSort(x => x.Age).ThenBy(x => x.Name).ToList();
我坚持使用keySelector
.我需要按选定的属性(例如Age
)比较项目
I'm stuck with the keySelector
. I need to compare the items by the selected property (e.g. Age
)
问题:比较器的正确语法是什么?
Question: What's how is the correct syntax for my comparer?
推荐答案
现在...正确地执行OrderBy
就像别人所说的那样是困难的...这是我在15分钟内编写的实现...
Now... Doing correctly a OrderBy
as other said is difficult... this is an implementation I wrote in 15 minutes...
public static class MyOrderedEnumerable
{
public static IOrderedEnumerable<TSource> MyOrderBy<TSource, TKey>(this IEnumerable<TSource> source, Func<TSource, TKey> keySelector, IComparer<TKey> comparer = null)
{
if (source == null)
{
throw new ArgumentNullException();
}
if (keySelector == null)
{
throw new ArgumentNullException();
}
if (comparer == null)
{
comparer = Comparer<TKey>.Default;
}
Comparison<TSource> comparer2 = (x, y) => comparer.Compare(keySelector(x), keySelector(y));
return new OrderedEnumerableImpl<TSource>(source, comparer2);
}
public static IOrderedEnumerable<TSource> MyOrderByDescending<TSource, TKey>(this IEnumerable<TSource> source, Func<TSource, TKey> keySelector, IComparer<TKey> comparer = null)
{
if (source == null)
{
throw new ArgumentNullException();
}
if (keySelector == null)
{
throw new ArgumentNullException();
}
if (comparer == null)
{
comparer = Comparer<TKey>.Default;
}
Comparison<TSource> comparer2 = (x, y) => comparer.Compare(keySelector(y), keySelector(x));
return new OrderedEnumerableImpl<TSource>(source, comparer2);
}
private class OrderedEnumerableImpl<TSource> : IOrderedEnumerable<TSource>
{
private readonly IEnumerable<TSource> Source;
private readonly Comparison<TSource> Comparer;
public OrderedEnumerableImpl(IEnumerable<TSource> source, Comparison<TSource> comparer)
{
Source = source;
Comparer = comparer;
}
public IOrderedEnumerable<TSource> CreateOrderedEnumerable<TKey>(Func<TSource, TKey> keySelector, IComparer<TKey> comparer, bool descending)
{
if (comparer == null)
{
comparer = Comparer<TKey>.Default;
}
Comparison<TSource> comparer2;
if (descending)
{
comparer2 = (x, y) =>
{
int result = Comparer(x, y);
if (result == 0)
{
result = comparer.Compare(keySelector(y), keySelector(x));
}
return result;
};
}
else
{
comparer2 = (x, y) =>
{
int result = Comparer(x, y);
if (result == 0)
{
result = comparer.Compare(keySelector(x), keySelector(y));
}
return result;
};
}
return new OrderedEnumerableImpl<TSource>(Source, comparer2);
}
public IEnumerator<TSource> GetEnumerator()
{
var source = Source.ToArray();
// ** Here you do the sorting! **
Array.Sort(source, Comparer);
for (int i = 0; i < source.Length; i++)
{
yield return source[i];
}
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
}
看到了** Here you do the sorting! **
吗?在那里,您必须插入排序算法.如您所见,有一个OrderedEnumerableImpl
类负责实现.关键是ThenBy
使用CreateOrderedEnumerable
方法.此方法通过将比较器链接到OrderBy
的基本比较器来修改排序算法. 但是这里有一点:您不能真正修改顺序,因为可以:
See the ** Here you do the sorting! **
? There you have to plug your sort algorithm. As you can see, there is an OrderedEnumerableImpl
class that does the implementation. The point is that the ThenBy
uses the CreateOrderedEnumerable
method. This method modifies the sorting algorithm, by chaining its comparer to the base comparer of the OrderBy
. but there is a point here: you can't really modify the ordering, because one could:
var myorderedcoll = mycoll.OrderBy(x => x.Foo);
var mysubordered1 = myorderedcoll.ThenBy(x => x.Bar1);
var mysubordered2 = myorderedcoll.ThenBy(x => x.Bar2);
很明显mysubordered1
由Foo+Bar1
排序,而mysubordered2
由Foo+Bar2
排序!
Clearly mysubordered1
is ordered by Foo+Bar1
, while mysubordered2
is ordered by Foo+Bar2
!
因此CreateOrderedEnumerable
通过获取已经存在的比较器并添加新的比较器来创建新的OrderedEnumerableImpl
类(请参见CreateOrderedEnumerable
的最后一行)
So CreateOrderedEnumerable
creates a new OrderedEnumerableImpl
class, by taking the comparer already present and adding the new comparer (see the last line of CreateOrderedEnumerable
)
请注意,您将此类用作:
Note that you use this class as:
var myorderedcoll = mycoll.MyOrderBy(x => x.Foo).ThenBy(x => x.Bar);
以此类推.
请注意,实际"实现要复杂得多.如所写,此实现每次进行比较时都会重新计算key
.实际的实现会预先计算所有必要的键,以加快比较速度.
Note that a "real" implementation is much more complex. As written, this implementation recalculates the key
each time it does a comparison. Real implementations precalculate all the necessary keys to speedup the comparisons.
对于排序,请使用 Wiki :
public IEnumerator<TSource> GetEnumerator()
{
var source = Source.ToArray();
// Taken from http://en.wikipedia.org/wiki/Bubble_sort#Pseudocode_implementation
int n = source.Length;
do
{
int newn = 0;
for (int i = 1; i <= n - 1; i++)
{
if (Comparer(source[i - 1], source[i]) > 0)
{
TSource temp = source[i - 1];
source[i - 1] = source[i];
source[i] = temp;
newn = i;
}
}
n = newn;
}
while (n != 0);
for (int i = 0; i < source.Length; i++)
{
yield return source[i];
}
}
这也是可以优化的:如果我们反转Bubblesort并在数组的顶部"中累积有序元素,那么对于bubbleort yield return
的每个循环,我们可以使用一个元素.这将缩短拥有第一个元素所需的时间.因此,如果您执行OrderBy(x => x.Foo).First()
,则不会对所有集合进行排序.
This too could be optimized: if we reverse the bubblesort and accumulate the ordered elements in the "top" of the array, then we can for each cycle of bubblesort yield return
one element. This will shorten the time needed to have the first element. So if you do OrderBy(x => x.Foo).First()
, not all the collection will be sorted.
这篇关于自定义Lambda排序扩展的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!