我正在创建一个服务,以方便用户从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);
}