所以这个问题是关于静态集合的.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()
仅投影列表中的一个项目。
所以我在这里有一个双重问题:
.Select()
,可以做我想做的事情?答案 0 :(得分:3)
一种通用解决方案甚至可以很好地转换为SQL(如果这是一个问题)将使用Skip
和Take
。您可以跳过第一个n-1
项,然后从原始1
(或IEnumerable
)中获取IQueryable
。
var original = Enumerable.Range(0, 1000);
var onlyOneItem = original.Skip(898 - 1).Take(1).Select(aMethod);
Skip
和Take
是Linq相当于SQL的OFFSET
和LIMIT
。
在一个类似于您的示例的简化案例中,您不会看到对性能的任何改进,但如果您在实际应用程序中有一个昂贵的查询,这样就可以避免获取任何不必要的元素
答案 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
}
}