ค้นหา () กับที่ไหน () 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

@ โบสถ์ฉันเดาว่าคำถามต่อไปของฉันจะเป็นเพราะเหตุใดพวกเขาจึงเพิ่มการค้นหาเลย นั่นเป็นเคล็ดลับที่ดี สิ่งเดียวที่ฉันคิดได้ก็คือ FirstOrDefault สามารถส่งคืนค่าเริ่มต้นอื่นที่ไม่ใช่ null ได้ ไม่อย่างนั้นมันก็ดูเหมือนว่าเป็นการเติมที่ไร้จุดหมาย
KingOfHypocrites

8
Findถือกำเนิด LINQ (มันมีอยู่ใน. NET 2.0 และคุณไม่สามารถใช้ lambdas ได้คุณถูกบังคับให้ใช้วิธีการปกติหรือวิธีการที่ไม่ระบุตัวตน)
Kirk Woll

คำตอบ:


205

เป็นที่FindวิธีการในIEnumerable<T>? (คำถามเชิงโวหาร)

WhereและFirstOrDefaultวิธีการมีผลบังคับใช้กับหลายชนิดของลำดับรวมทั้งList<T>, T[], Collection<T>ฯลฯ ลำดับการดำเนินการใด ๆ ที่IEnumerable<T>สามารถใช้วิธีการเหล่านี้ จะใช้ได้เฉพาะสำหรับFind List<T>โดยทั่วไปแล้ววิธีการที่ใช้งานได้มากกว่านั้นสามารถนำมาใช้ซ้ำได้มากกว่าและมีผลกระทบมากกว่า

ฉันเดาว่าคำถามต่อไปของฉันจะเป็นเพราะเหตุใดพวกเขาจึงเพิ่มการค้นหาเลย นั่นเป็นเคล็ดลับที่ดี สิ่งเดียวที่ฉันคิดได้ก็คือ FirstOrDefault สามารถส่งคืนค่าเริ่มต้นอื่นที่ไม่ใช่ null ได้ ไม่อย่างนั้นมันก็ดูเหมือนว่าเป็นการเติมที่ไร้จุดหมาย

Findเมื่อList<T>ถือกำเนิดวิธีการอื่น ๆ List<T>ถูกเพิ่มด้วย generics ใน. NET 2.0 และFindเป็นส่วนหนึ่งของ API สำหรับคลาสนั้น WhereและFirstOrDefaultถูกเพิ่มเป็นวิธีการขยายสำหรับIEnumerable<T>กับ Linq ซึ่งเป็นรุ่นที่ใหม่กว่า. NET ฉันไม่สามารถพูดด้วยความมั่นใจได้ว่าถ้า Linq มีอยู่ในรุ่น 2.0 ที่Findไม่เคยถูกเพิ่มเข้ามา แต่เป็นกรณีของคุณสมบัติอื่น ๆ ที่มาใน. NET รุ่นก่อนหน้าซึ่งล้าสมัยหรือซ้ำซ้อนโดยรุ่นที่ใหม่กว่า


85
เพียงเพื่อเติมเต็ม: ไม่จำเป็นต้องโทรหา Where and First หรือ FirstOrDefault: First หรือ FirstOrDefault อนุญาตให้คุณระบุการค้นหาคำกริยาทำให้การโทร Where Where ไม่จำเป็น
Robson Rocha

4
แต่Where(condition).FirstOrDefault()เพิ่มประสิทธิภาพอย่างน้อยเช่นกันและบางครั้งก็ดีกว่าFirstOrDefault(condition)คนเดียว เรามักจะใช้Where()เพื่อเพิ่มประสิทธิภาพเมื่อมีให้
Suncat2000

7
@ Suncat2000 โปรดยกตัวอย่าง
Konstantin Salavatov

2
@ Suncat2000 คุณกำลังใช้ Linq เนื่องจากพลังที่แสดงออกและต้องการเขียนโค้ดที่ประกาศ คุณไม่ควรกังวลกับการปรับปรุงขนาดเล็กดังกล่าวซึ่งสามารถเปลี่ยนแปลงได้ในการใช้งานในอนาคต อย่าเพิ่มประสิทธิภาพเร็วเกินไป
Piotr Falkowski

50

ฉันเพิ่งค้นพบในวันนี้ทำแบบทดสอบบางอย่างเกี่ยวกับรายชื่อของวัตถุ 80K และพบว่าFind()สามารถเป็นได้ถึง 1000% เร็วกว่าการใช้ด้วยWhere FirstOrDefault()ฉันไม่รู้ว่าจนกว่าจะทดสอบตัวจับเวลาก่อนและหลังทั้งหมด บางครั้งมันเป็นเวลาเดียวกันมิฉะนั้นมันก็เร็วขึ้น


6
คุณลองกับ Where AND FirstOrDefault หรือไม่? หากคุณลองใช้เพียงแค่ FirstOrDefault และดูว่า Find () ยังดีกว่าอยู่หรือไม่
MVCKarl

5
ดูเหมือนว่าคุณไม่ได้แสดงผลลัพธ์ด้วย.ToList()หรือ.ToArray()เพื่อดำเนินการค้นหาจริง
Andrew Morton

4
มันเป็นเพราะFindทำให้การใช้คีย์หลัก (เพราะฉะนั้นดัชนี) ในขณะที่Whereเป็นแบบสอบถาม SQL ธรรมดา
percebus

4
ในฐานะของ EF6, Find และ FirstOrDefault ทั้งคู่จะสร้างคำสั่ง SQL เดียวกันทั้งหมด คุณสามารถเห็น SQL ในแอปคอนโซลโดยทำ context.Database.Log = Console.Write ตัวอย่างที่อ้างถึงนั้นใช้หน่วยความจำ "ค้นหา" กับรายการสตริงไม่ใช่การเทียบเคียงกับฐานข้อมูลด้วยคีย์หลัก บางทีคำแปลของประโยคค้นหา - ซึ่งไม่จำเป็นต้องทำการแยกนิพจน์แลมบ์ดาเป็นเหตุผลสำหรับการปรับปรุงประสิทธิภาพในกรณีนี้ เทียบกับฐานข้อมูลฉันสงสัยว่าคุณจะสังเกตเห็นความแตกต่างในสถานการณ์ RL ... ฉันยังสงสัยว่ามันได้รับการทดสอบโดยใช้การค้นหาครั้งแรกแทนที่จะเป็นที่สอง ...
C.List

2
การปรับปรุงประสิทธิภาพนี้เป็นเพราะ find () ตรวจสอบแคชของวัตถุก่อนที่จะกดปุ่ม DB ในขณะที่ () เสมอไปที่ DB เพื่อรับวัตถุ
Gaurav

35

มีความแตกต่างที่สำคัญมากหากแหล่งข้อมูลคือ Entity Framework: Findจะค้นหาเอนทิตีในสถานะ 'เพิ่ม' ที่ยังไม่ยืนยัน แต่Whereจะไม่ นี่คือโดยการออกแบบ



1

นอกเหนือจากแอนโทนี่ตอบรับการ Where()เยี่ยมชมผ่านบันทึกทั้งหมดแล้วกลับผลลัพธ์ (s) ในขณะที่Find()ไม่จำเป็นต้องสำรวจผ่านบันทึกทั้งหมดถ้าตรงกับภาคที่กำหนด

ดังนั้นสมมติว่าคุณมี List of Test คลาสที่มีidและnameคุณสมบัติ

 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ครั้งเท่านั้นที่จำเป็นในการให้ผลลัพธ์ แต่ถ้าคุณใช้Where().FirstOrDefault()เราจะไปที่บันทึกทั้งหมดแล้วเราจะได้ผลลัพธ์

ดังนั้นเมื่อคุณรู้ว่าคุณต้องการเพียงผลลัพธ์แรกจากการบันทึกในคอลเลกชันFind()จะเหมาะสมกว่าแล้วWhere().FirtorDefault();


4
แต่ถ้าคุณใช้ Where () FirstOrDefault () เราจะไปที่บันทึกทั้งหมดแล้วเราจะได้ผลลัพธ์ Nope FirstOrDefaultจะ 'เพิ่มฟอง' ห่วงโซ่และหยุดการแจกแจงทุกอย่าง ฉันใช้คำว่า 'bubble-up' เพราะขาดการแสดงออกที่ดีกว่าเพราะจริงๆแล้วทุก ๆ ตัวเลือก / เพรดิเคตจะถูกส่งต่อไปยังถัดไปดังนั้นวิธีสุดท้ายในการทำโซ่ก็คือการทำงานก่อน
Silvermind

1

ว้าวฉันเพิ่งดูบทเรียนของ EF จาก MicrosofToolbox ในวันนี้บน Youtube เขาพูดเกี่ยวกับการใช้ Find () และ FirstOrDefault (เงื่อนไข) ในการสืบค้นและ Find () จะค้นหาข้อมูลที่คุณได้ทำบางสิ่งบนวัตถุนั้น (เพิ่มหรือแก้ไขหรือลบ - แต่ยังไม่ได้บันทึกลงในฐานข้อมูล) ในขณะที่ FirstOrDefault เท่านั้น ค้นหาสิ่งที่ถูกบันทึกไว้แล้ว


-1

Find()เป็นเทียบเท่า IEnumerable FirstOrDefault()ของ คุณไม่ควรเชื่อมโยงทั้ง. Where () กับเข้าด้วยกัน.FirstOrDefault()เพราะ.Where()จะผ่านอาร์เรย์ทั้งหมดแล้วจะวนซ้ำในรายการนั้นเพื่อค้นหารายการแรก คุณประหยัดเวลาได้อย่างเหลือเชื่อด้วยการใส่คำค้นหาลงในFirstOrDefault()เมธอด

นอกจากนี้ฉันขอแนะนำให้คุณอ่านคำถามที่เชื่อมโยงกับเธรดนี้เพื่อเรียนรู้เพิ่มเติมเกี่ยวกับประสิทธิภาพที่ดีขึ้นของการใช้.Find()ในสถานการณ์เฉพาะประสิทธิภาพของการค้นหา () กับ FirstOrDefault ()


นี่เป็นคำตอบที่ซ้ำกันข้างบนของคุณ นอกจากนี้ดูความคิดเห็นของ Silvermind เกี่ยวกับคำตอบนั้น
carlin.scott
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.