如何有效地限制结果,然后将其与linq/lambda表达式连接



我正在创建一个服务,以方便用户从IANA-协议注册表中选择协议。

正如您可能想象的那样,在注册表中搜索术语http会得到很多点击。由于用户选择amt-soap-http的频率比直接选择http的频率低得多,我决定最好将以http开始的所有内容都提取出来,然后将其与其余结果连接起来。

下面的lambda表达式是这个思考过程的结果:

var records = this._ianaRegistryService.GetAllLike(term).ToList();
var results = records.Where(r => r.Name.StartsWith(term))
                     .OrderBy(r => r.Name)
                     .Concat(records.Where(r => !r.Name.StartsWith(term))
                                    .OrderBy(r => r.Name))
                     .Take(MaxResultSize);

不幸的是,我觉得我对结果的迭代次数超过了必要的次数。撇开过早的优化考虑不谈,lambda表达式的组合是否比上面的更有效?

两步排序可能更有效:

var results = records.OrderBy(r => r.Name.StartsWith(term) ? 1 : 2)
                     .ThenBy(r => r.Name)
                     .Take(MaxResultSize);

使用注释来解释我要做的事情越来越难了。所以我将发布另一个答案。假设我想先根据随机整数的偶数或奇数,然后按数字顺序对其进行排序(用mod 2模拟StartsWith)。

以下是测试用例:action2与其他答案相同。

如果你运行这个代码,你会发现我的建议(action1)快了两倍。

void Test()
{
    Random rnd = new Random();
    List<int> records = new List<int>();
    for(int i=0;i<2000000;i++)
    {
        records.Add(rnd.Next());
    }
    Action action1 = () =>
    {
        var res1 = records.GroupBy(r => r % 2)
                    .OrderBy(x => x.Key)
                    .Select(x => x.OrderBy(y => y))
                    .SelectMany(x => x)
                    .ToList();
    };
    Action action2 = () =>
    {
        var res2 = records.OrderBy(x => x % 2).ThenBy(x => x).ToList();
    };

    //Avoid counting JIT
    action1();
    action2();

    var sw = Stopwatch.StartNew();
    action1();
    long t1 = sw.ElapsedMilliseconds;
    sw.Restart();
    action2();
    long t2 = sw.ElapsedMilliseconds;
    Console.WriteLine(t1 + " " + t2);
}

最新更新