Find()与Where()。FirstOrDefault()


161

我经常看到人们Where.FirstOrDefault()用来搜索并获取第一个元素。为什么不只是使用Find()?对方有优势吗?我无法分辨。

namespace LinqFindVsWhere
{
    class Program
    {
        static void Main(string[] args)
        {
            List<string> list = new List<string>();
            list.AddRange(new string[]
            {
                "item1",
                "item2",
                "item3",
                "item4"
            });

            string item2 = list.Find(x => x == "item2");
            Console.WriteLine(item2 == null ? "not found" : "found");
            string item3 = list.Where(x => x == "item3").FirstOrDefault();
            Console.WriteLine(item3 == null ? "not found" : "found");
            Console.ReadKey();
        }
    }
}

45
FWIW list.FirstOrDefault(x => x == "item3");比同时使用.Where和更简洁.FirstOrDefault
Kirk Woll '02

@柯克,我想我的下一个问题是他们为什么要完全添加发现。那是一个很好的提示。我唯一想到的是FirstOrDefault可以返回除null以外的其他默认值。否则,这似乎毫无意义。
KingHypocrites 2012年

8
Find早于LINQ。(它在.NET 2.0中可用,您不能使用lambda。您被迫使用常规方法或匿名方法)
Kirk Woll 2012年

Answers:


204

在哪里Find上的方法IEnumerable<T>?(反问的问题。)

WhereFirstOrDefault方法可应用于对多种序列,包括List<T>T[]Collection<T>等。任何顺序实现IEnumerable<T>可以使用这些方法。Find仅适用于List<T>。通常更适用的方法将更可重用,并且影响更大。

我想我的下一个问题是他们为什么要完全添加发现。那是一个很好的提示。我唯一想到的是,FirstOrDefault可以返回除null以外的其他默认值。否则,这似乎毫无意义。

FindList<T>其他方法之前。List<T>在.NET 2.0中添加了泛型,并且Find是该类API的一部分。WhereFirstOrDefault作为IEnumerable<T>Linq(一种更高的.NET版本)的扩展方法添加。我不能肯定地说,如果Linq在2.0版中存在,那Find将永远不会被添加,但是对于早期.NET版本中的许多其他功能,后来的版本已过时或多余,可以说是这样。


85
只是为了补充:无需调用Where和First或FirstOrDefault:First或FirstOrDefault允许您指定搜索谓词,从而无需使用Where调用
Robson Rocha

4
但是Where(condition).FirstOrDefault()优化至少也是如此,有时甚至比FirstOrDefault(condition)单独优化更好。Where()如果有的话,我们总是使用以获得改进的性能。
Suncat2000

7
@ Suncat2000请提供示例
Konstantin Salavatov '19

2
@ Suncat2000您正在使用Linq,因为它具有强大的表达能力,并且想要编写声明性代码。您不必担心这种微小的改进,这些改进也会在将来的实现中发生变化。另外,不要太早进行优化
Piotr Falkowski

50

我今天才发现,对80K个对象列表进行了一些测试,发现它Find()比使用Wherewith 可以快1000%FirstOrDefault()。我不知道这一切,直到之前和之后都测试了一个计时器。有时是同一时间,否则更快。


6
您是否尝试使用Where AND FirstOrDefault?如果您仅使用FirstOrDefault尝试了一下,看看Find()是否仍然更好。
MVCKarl 2012年

5
听起来您没有使用.ToList().ToArray()实现实际执行查询的结果。
安德鲁·莫顿

4
这是因为Find利用了主键(因此使用了索引),而这Where是一个普通的sql查询
percebus's

4
从EF6开始,Find和FirstOrDefault都生成完全相同的SQL语句。您可以通过执行context.Database.Log = Console.Write;在控制台应用程序中查看SQL。该站点示例对字符串列表使用内存中的“查找”,而不是对具有主键的数据库使用。也许Find子句的语句翻译-无需进行lambda表达式解析,这是这种情况下性能提高的原因。针对数据库,我怀疑您会注意到RL情况是否有所不同...我也想知道是否已使用“查找第一”而不是第二查找对它进行了测试...
C.List

2
好吧,这种性能的提高是因为find()在命中数据库之前先检查对象的缓存,而where()总是去DB获取对象
Gaurav,

35

如果数据源是实体框架,则有一个非常重要的区别: Find将查找处于“已添加”状态但尚未持久的实体,但Where不会持久。这是设计使然。



1

除了Anthony回答 Where()访问所有记录,然后返回结果,Find()如果谓词与给定谓词匹配,则无需遍历所有记录。

所以说您有具有idname属性的Test类的List 。

 List<Test> tests = new List<Test>();
 tests.Add(new Test() { Id = 1, Name = "name1" });
 tests.Add(new Test() { Id = 2, Name = "name2" });
 tests.Add(new Test() { Id = 3, Name = "name3" });
 tests.Add(new Test() { Id = 4, Name = "name2" }); 
 var r = tests.Find(p => p.Name == "name2");
 Console.WriteLine(r.Id);

将给出输出2,只有2次访问。Find需要给出结果,但是如果您使用,Where().FirstOrDefault()我们将访问所有记录,然后得到结果。

因此,当您知道只希望集合中记录的第一个结果Find()更合适时,Where().FirtorDefault();


4
但是,如果您使用Where()。FirstOrDefault(),我们将访问所有记录,然后得到结果。不。FirstOrDefault将“弄乱”链条,并停止枚举所有内容。由于缺乏更好的表达,我使用了“冒泡”一词,因为实际上每个选择器/谓词都会传递给下一个,因此链中的最后一个方法实际上首先执行工作。
Silvermind

1

哇,我今天才在Youtube上观看MicrosofToolbox的EF教程。他确实说过要在查询中使用Find()和FirstOrDefault(condition),并且Find()将搜索您对该对象执行过某些操作的数据(添加或编辑或删除-但尚未保存到数据库中),而FirstOrDefault仅会寻找已经保存的内容


-1

Find()是的IEnumerable等效项FirstOrDefault()。您不应该同时链接两个.Where(),.FirstOrDefault()因为它们.Where()会遍历整个数组,然后将遍历该列表以查找第一项。通过将搜索谓词放入该FirstOrDefault()方法,可以节省大量时间。

另外,我鼓励您阅读此线程的链接问题,以了解.Find()在特定情况下使用Find()与FirstOrDefault()的性能有关的更好性能。


这是您上面答案的重复。另外,请参见Silvermind关于该答案的评论。
carlin.scott
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.