如何改进LINQ?

时间:2016-06-02 07:22:49

标签: c# linq select where

所以这个问题是关于静态集合的.Select()语句(即不是Select()Where()或其他LINQ操作的结果,例如List array)。

我的印象是,当使用.Select()或其他非过滤,非排序方法时,.ElementAt()将从原始集合中获取元素并通过{{1}运行它}。我认为这是最好的方法,因为.Select只返回一个元素而LINQ不会缓存任何内容,所以其他生成的项目都会被抛弃。

举个例子:

.ElementAt()

为了在更大的图片中看到这一点,如果我有一个20K项目的列表,我只需要n th 项目,但我执行的是一个非常重的var original = Enumerable.Range(0, 1000); var listWithADifficultSelect = original.Select(aMethod); var onlyOneItem = listWithADifficultSelect.ElementAt(898); object aMethod(int number) { // Gets the item from some kind of database, difficult operation // Takes at least a few milliseconds return new object(); } ,我希望.Select()仅投影列表中的一个项目。

所以我在这里有一个双重问题:

  1. 为什么这样建?
  2. 有没有办法建立一个改进的.Select(),可以做我想做的事情?

2 个答案:

答案 0 :(得分:3)

一种通用解决方案甚至可以很好地转换为SQL(如果这是一个问题)将使用SkipTake。您可以跳过第一个n-1项,然后从原始1(或IEnumerable)中获取IQueryable

var original = Enumerable.Range(0, 1000);
var onlyOneItem = original.Skip(898 - 1).Take(1).Select(aMethod);

SkipTake是Linq相当于SQL的OFFSETLIMIT

在一个类似于您的示例的简化案例中,您不会看到对性能的任何改进,但如果您在实际应用程序中有一个昂贵的查询,这样就可以避免获取任何不必要的元素

答案 1 :(得分:1)

如果我正确理解你的问题,你不希望LINQ为前897个元素调用aMethod,如果你只需要第898个元素。

那么你为什么不这样称呼它:

var onlyOneItem = aMethod(original.ElementAt(898));

如果您想获得几个特定元素,并且不希望LINQ一直重新评估aMethod,那么将结果转换为List或数组:

var listWithADifficultSelect = original.Select(aMethod).ToList(); // or ToArray();

Select所有aMethod次调用只执行一次,您可以访问所有元素而无需重新调用aMethod

如果你想编写自己的LINQ方法,比LINQ做的更多,你可以轻松实现自己的扩展:

public static class MyLinq
{
    public static IEnumerable<TResult> MySelect<TSource,TResult>(this IEnumerable<TSource>, Func<TSource,TResult> selector)
    {
        // implement yourself
    }
    public static TSource MyElementAt<TSource>(this IEnumerable<TSource>, int index)
    {
        // implement yourself
    }
}