Lou*_*hys 2 .net c# linq sorting sql-order-by
我想使用可能需要一些时间来计算的值对对象列表进行排序。现在我有这样的代码:
public IEnumerable<Foo> SortFoo(IEnumerable<Foo> original)
{
return foos.OrderByDescending(foo => CalculateBar(foo));
}
private int CalculateBar(Foo foo)
{
//some slow process here
}
Run Code Online (Sandbox Code Playgroud)
上面的代码的问题在于,它将为每个项目多次调用计算值,这不好。可能的优化是使用缓存的值(可能是字典),但这将意味着SortFoo在每次排序后都必须清除缓存(以避免内存泄漏,我确实希望在每次SortFoo调用时重新计算该值)。
有没有更清洁,更优雅的解决方案?
似乎.OrderBy()已经针对slow keySelectors进行了优化。
基于以下内容,.OrderBy()似乎缓存了keySelector您提供的委托的结果。
var random = new Random(0);
var ordered = Enumerable
.Range(0, 10)
.OrderBy(x => {
var result = random.Next(20);
Console.WriteLine("keySelector({0}) => {1}", x, result);
return result;
});
Console.WriteLine(String.Join(", ", ordered));
Run Code Online (Sandbox Code Playgroud)
这是输出:
keySelector(0) => 14
keySelector(1) => 16
keySelector(2) => 15
keySelector(3) => 11
keySelector(4) => 4
keySelector(5) => 11
keySelector(6) => 18
keySelector(7) => 8
keySelector(8) => 19
keySelector(9) => 5
4, 9, 7, 3, 5, 0, 2, 1, 6, 8
Run Code Online (Sandbox Code Playgroud)
如果每次比较都运行一次委托,我会看到keySelector每个项目不止一次调用我的委托。
因为每个项目在某种情况下会多次与其他项目进行比较,所以您可以便宜地将计算至少每个项目缓存一次。如果您经常对相同的值运行计算,则最好记住该功能,
public IEnumerable<Foo> SortFoo(IEnumerable<Foo> original)
{
return foos
.Select(f => new { Foo = f, SortBy = CalculateBar(f) })
.OrderByDescending(f=> f.SortBy)
.Select(f => f.Foo);
}
Run Code Online (Sandbox Code Playgroud)
这会将计算减少到每个项目一次
| 归档时间: |
|
| 查看次数: |
2868 次 |
| 最近记录: |