试图弄清楚如何在不使用LINQ的情况下进行快速复杂的排序

时间:2018-07-04 23:12:12

标签: c# sorting

我想我也很习惯使用LINQ,但这很慢,我确实使用了探查器,它消耗了我尝试执行的时间的65%

var unlock = Locked.OrderBy(x => x.Weight) //double
                   .ThenByDescending(x => x.Stuff?.Level ?? 100) //int
                   .ThenBy(x => x.Penalty) //double
                   .FirstOrDefault();

Locked是一个列表,我知道排序会更改列表,但是我并不在乎,我只是想使其工作(如果可能),下面的代码不会提供与上面的LINQ相同的结果;

Locked.Sort(delegate (Node a, Node b)
{
    int xdiff = a.Weight.CompareTo(b.Weight);

    if (xdiff != 0) return xdiff;

    var aStuff = a.Stuff?.Level ?? 100;
    var bStuff = b.Stuff?.Level ?? 100;

    xdiff = -1 * aStuff.CompareTo(bStuff);

    if (xdiff != 0) return xdiff;

    return xdiff = a.Penalty.CompareTo(b.Penalty);
});

var unlock = Locked[0];

第一件事是,可以使用List.Sort进行 complex 排序吗?升序/先降序/再升序?

如果是,我的错误在哪里?

接下来是,有没有一种更快的方式来做我想做的事情?

3 个答案:

答案 0 :(得分:9)

如果您紧跟在“第一或默认”(最小/最大)之后,则无需排序-您可以通过一次O(N)传递来进行此操作。选择第一项并将其存储在变量中;现在依次遍历所有 other 项:如果根据您的标准更可取:将其放入变量中。当您走到尽头时,您就有了赢家。

答案 1 :(得分:2)

您可以创建一个自定义比较器:

var comparer = Comparer<SomeItem>.Create((a, b) => 
    a.A == a.B 
        ? a.B == b.B 
            ? a.C == b.C 
                 ? 0 
                 : b.C - a.C //the order of these subtractions will affect the order
            : a.B - b.B 
        : a.A - b.A);

然后使用morelinqMinBy

IEnumerable<SomeItem> items = ...;
var best = items.MinBy(x => x, comparer); //.First() if it's morelinq3

...或者如果创建比较器看起来很吓人,我写了ComparerBuilder library来简化它:

var builder = new ComparerBuilder<Item>();
var comparer = builder
    .SortKey(x => x.A)
    .ThenKeyDescending(x => x.B)
    .ThenKey(x => x.C)
    .Build();
var selectedItem = items.MinBy(x => x, comparer).First();

答案 2 :(得分:0)

基于Mark的答案,我想到了这一点;

    Node unlock = null;
    Node locked = null;

    if (Locked.Count > 0)
    {
        unlock = Locked[0];
        for (var i = 1; i < Locked.Count; ++i)
        {
            locked = Locked[i];
            if (unlock.Weight > locked.Weight)
            {
                unlock = locked;
            }
            else if (unlock.Weight == locked.Weight)
            {
                var unlockStuffLevel = unlock.Stuff?.Level ?? 100;
                var lockedStuffLevel = locked.Stuff?.Level ?? 100;

                if (unlockStuffLevel < lockedStuffLevel)
                {
                    unlock = locked;
                }
                else if (unlockStuffLevel == lockedStuffLevel )
                {
                    if (unlock.Penalty > locked.Penalty)
                    {
                        unlock = locked;
                    }
                }
            }
        }
    }

分析表明,这现在需要大约15%的时间,而不是之前的65%,这似乎可以复制与LINQ相同的结果,我可能会在以后进行进一步的优化,但现在我有了想要的东西