自定义Lambda排序扩展 [英] Custom Lambda sort extension

查看:70
本文介绍了自定义Lambda排序扩展的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想使用我的自定义扩展方法来订购对象列表.这只是一个样本,因此使用了冒泡排序.我目前的状态:

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);

很明显mysubordered1Foo+Bar1排序,而mysubordered2Foo+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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆