我有一个与OrderBy和ThenBy
的linq查询(不是数据库相关的)var sortedList = unsortedList
.OrderBy(foo => foo.Bar) //this property access is relatively fast
.ThenBy(foo => foo.GetCurrentValue()) //this method execution is slow
获取foo.Bar
的速度很快,但执行foo.GetCurrentValue()
非常慢。返回值仅在某些成员具有相等的Bar值时才重要,这种情况很少发生,但在发生这种情况时需要考虑。是否可以选择仅在需要在相等Bar值的情况下进行平局时执行ThenBy子句? (即如果foo.Bar值是唯一的,则不会执行。)
另外,实际上Bar也有点慢,所以最好不要为同一个对象调用它两次。
答案 0 :(得分:5)
由于您不在数据库中,并且需要严格控制排序,因此您可以将单个OrderBy与自定义IComparer一起使用,该IComparer仅访问它所需的内容,并且不执行不必要的评估。
答案 1 :(得分:4)
这有点笨拙,但我确信它可以改进 - 也许它不会在一个linq语句中完成,但它应该有效:
var sortedList2 = unsortedList
.OrderBy(foo => foo.Bar)
.GroupBy(foo => foo.Bar);
var result = new List<Foo>();
foreach (var s in sortedList2)
{
if (s.Count() > 1)
{
var ordered = s
.OrderBy(el => el.GetCurrentValue());
result.AddRange(ordered);
}
else
{
result.AddRange(s);
}
}
更新:
我们可以争论这是否有所改善,但它至少看起来更简洁:
var list3 = (from s in sortedList2
let x = s.Count()
select x == 1
? s.Select(el => el)
: s.OrderBy(el => el.GetCurrentValue()))
.SelectMany(n => n);
<强> UPDATE2:强>
您可以使用Skip(1).Any()
代替Count()
- 这应该避免我猜测整个序列的枚举。
答案 2 :(得分:1)
var query = unsortedList
.GroupBy(foo => foo.Bar)
.OrderBy(g => g.Key)
.SelectMany(g => g.Skip(1).Any() ? g.OrderBy(foo => foo.GetCurrentValue()) : g);
这有明显的缺点,即不返回IOrderedEnumerable<Foo>
答案 3 :(得分:0)
试试这个
var sortedList = unsortedList.OrderBy(foo => foo.Bar);
if(some_Condition)
{
sortedList = sortedList.OrderBy(foo => foo.GetCurrentValue());
}
答案 4 :(得分:0)
我改变了Joanna Turban的解决方案并开发了以下扩展方法:
public static IEnumerable<TSource> OrderByThenBy<TSource, TKey>(this IEnumerable<TSource> source, Func<TSource, TKey> orderBy, Func<TSource, TKey> thenBy)
{
var sorted = source
.Select(s => new Tuple<TSource, TKey>(s, orderBy(s)))
.OrderBy(s => s.Item2)
.GroupBy(s => s.Item2);
var result = new List<TSource>();
foreach (var s in sorted)
{
if (s.Count() > 1)
result.AddRange(s.Select(p => p.Item1).OrderBy(thenBy));
else
result.Add(s.First().Item1);
}
return result;
}