代码之家  ›  专栏  ›  技术社区  ›  Fredou

试图找出如何在没有linq的情况下进行快速复杂排序

  •  1
  • Fredou  · 技术社区  · 6 年前

    我想我太习惯使用linq了,但这很慢,我确实使用了一个profiler,它花费了我65%的时间来做我想做的事情。

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

    锁定是一个列表,我知道排序会改变列表,但我并不真的在乎,我只是想让它工作(如果可能的话),下面的代码不会给出与上面的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];
    

    第一件事是,名单上有没有可能。整理一下 复杂的 分类?ASC/然后是DESC/然后是ASC?

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

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

    3 回复  |  直到 6 年前
        1
  •  9
  •   Marc Gravell    6 年前

    如果你只是在“第一个或默认”(最小/最大)之后,你不需要排序-你可以在一个o(n)过程中完成。选择第一个项并将其存储在变量中;现在循环所有 其他 项目依次:如果根据您的条件更可取:将其放入变量中。当你走到最后,你就有了赢家。

        2
  •  3
  •   spender    6 年前

    可以创建自定义比较器:

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

    然后使用 morelinq MinBy 以下内容:

    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();
    
        3
  •  0
  •   Fredou    6 年前

    根据马克的回答,我想到了这个;

        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相同的结果,我可能会在稍后对其进行改进,但现在我得到了我想要的