2

我有一个带有 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 也有点慢,所以最好不要为同一个对象调用两次。

4

5 回答 5

5

由于您不在数据库中,并且您需要对排序进行严格控制,因此您可以将单个 OrderBy 与自定义 IComparer 一起使用,该 IComparer 仅访问它需要的内容,而不执行不必要的评估。

于 2012-05-22T03:43:45.837 回答
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);

更新2:

您可以使用Skip(1).Any()代替Count()- 这应该避免我猜想的整个序列的枚举。

于 2012-05-22T07:13:58.020 回答
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>

于 2012-05-23T14:13:06.480 回答
0

试试这个

var sortedList = unsortedList.OrderBy(foo => foo.Bar);

if(some_Condition)
{ 
   sortedList = sortedList.OrderBy(foo => foo.GetCurrentValue()); 
}
于 2012-05-22T03:43:18.633 回答
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;
}
于 2013-02-08T01:49:00.143 回答