List<T>.Find() 的 LINQ 等效方法?

8
我正在查看一些代码,它接受一个 IEnumerable<T> 并将其转换为 List<T>,以便可以使用 List<T>.Find(predicate)
var myEnumerable = ...;
var myList = new List<T>(myEnumerable);
var match = myList.Find(value => value.Aaa == aaa && value.Bbb == bbb);

有没有一种使用LINQ扩展方法重写它的方法,具有相同的效果,但不需要构建额外的List<T>作为中间步骤?

FirstOrDefault(source, predicate)扩展方法看起来是一个很好的选择,但我试图弄清楚它是否与Find完全等效,这让我头疼。

3个回答

25

仅供参考,这是一张关于.NET 2风格的List<>实例方法的表格以及它们在Linq中等价的扩展方法:

METHOD IN List<>                              METHOD IN Linq
------------------------------------------------------------------------------------------

list.Contains(item)                           query.Contains(item)

list.Exists(x => x.IsInteresting())           query.Any(x => x.IsInteresting())
list.TrueForAll(x => x.IsInteresting())       query.All(x => x.IsInteresting())

list.Find(x => x.IsInteresting())             query.FirstOrDefault(x => x.IsInteresting())
list.FindLast(x => x.IsInteresting())         query.LastOrDefault(x => x.IsInteresting())

list.FindAll(x => x.IsInteresting())          query.Where(x => x.IsInteresting())

list.ConvertAll(x => x.ProjectToSomething())  query.Select(x => x.ProjectToSomething())

当然,它们中的一些并不完全等同。特别是 Linq 的 WhereSelect 使用延迟执行,而 List<>FindAllConvertAll 会立即执行并返回新的 List<> 实例的引用。

FindLast 通常比 LastOrDefault 更快,因为 FindLast 实际上从 List<> 的末尾开始搜索。另一方面,LastOrDefault(predicate) 总是遍历整个序列(从第一个项目开始),然后才返回最近的匹配项。


10
LINQ的等效方法是使用FirstOrDefault: FirstOrDefault
var match = myEnumerable.FirstOrDefault(value => value.Aaa == aaa && value.Bbb == bbb);

这正是我所怀疑的,但很高兴能从比我更有声望的人那里得到确认(微笑)。所以这确实以相同的方式处理所有边缘情况吗?(空集合、没有匹配项、任何其他异常情况) - Joe White
@Joe:是的。它将会给你相同的结果 - 第一个匹配项,或者在没有匹配元素的情况下返回 default(T)。它实际上是完全相同的,只不过它适用于任何 IEnumerable<T> - Reed Copsey

1

或者你可以采用以下方式:

var match = myEnumerable.Where(value => value.Aaa == aaa && value.Bbb == bbb)
                        .FirstOrDefault();

2
@danderson:不是这样的——LINQ使用延迟执行,因此只要找到第一个元素,“查询”就会停止执行。这实际上并不比直接使用FirstOrDefault低效多少[非常微小的差距]。仍然只有最多一次遍历序列... - Reed Copsey
我进行了一些性能测试并验证了这一点,但您是否也知道任何文章、白皮书或MSDN链接,可以解释LINQ在底层是如何工作的?我还没有在MSDN上找到相关的内容。 - David Anderson
2
@danderson - Jon Skeet有一系列包含42个部分的博客文章可以帮助你:http://msmvps.com/blogs/jon_skeet/archive/tags/Edulinq/default.aspx - saus
2
@Shibumi 真的吗?我恰恰相反。我总是使用 myEnumerable.FirstOrDefault(predicate) 而不是 myEnumerable.Where(predicate).FirstOrDefault(),因为我认为前者不仅更短,而且更清晰明了。 - Jeppe Stig Nielsen
@JeppeStigNielsen 我不能说我在2011年写的东西代表了我现在的编码哲学,也无法解释当时为什么会这样想。不过还是谢谢你的评论! - Shibumi
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接