Tìm () so với Where (). FirstOrDefault ()


161

Tôi thường thấy mọi người sử dụng Where.FirstOrDefault()để thực hiện tìm kiếm và lấy phần tử đầu tiên. Tại sao không chỉ sử dụng Find()? Có một lợi thế cho người khác? Tôi không thể nói sự khác biệt.

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");ngắn gọn hơn so với sử dụng cả hai .Where.FirstOrDefault.
Kirk Woll

@Kirk, tôi đoán câu hỏi tiếp theo của tôi sẽ là tại sao họ lại thêm tìm kiếm này. Đó là một mẹo tốt. Điều duy nhất tôi có thể nghĩ là FirstOrDefault có thể trả về một giá trị mặc định khác ngoài null. Nếu không, nó chỉ có vẻ như một bổ sung vô nghĩa.
KingOfHypocites 17/212

8
Findtrước LINQ. (nó có sẵn trong .NET 2.0 và bạn không thể sử dụng lambdas. Bạn đã buộc phải sử dụng các phương thức bình thường hoặc phương thức ẩn danh)
Kirk Woll

Câu trả lời:


204

Đâu là Findphương pháp trên IEnumerable<T>? (Câu hỏi tu từ.)

Các WhereFirstOrDefaultcác phương pháp được áp dụng chống lại nhiều loại trình tự, bao gồm List<T>, T[], Collection<T>vv chuỗi Bất kỳ mà cụ IEnumerable<T>có thể sử dụng các phương pháp này. Findchỉ có sẵn cho List<T>. Các phương pháp thường được áp dụng nhiều hơn, sau đó có thể tái sử dụng nhiều hơn và có tác động lớn hơn.

Tôi đoán câu hỏi tiếp theo của tôi sẽ là lý do tại sao họ thêm tìm thấy ở tất cả. Đó là một mẹo tốt. Điều duy nhất tôi có thể nghĩ là FirstOrDefault có thể trả về một giá trị mặc định khác ngoài null. Nếu không, nó chỉ là một bổ sung vô nghĩa

Findtrên List<T>các phương pháp khác. List<T>đã được thêm vào với generic trong .NET 2.0 và Findlà một phần của API cho lớp đó. WhereFirstOrDefaultđã được thêm vào dưới dạng các phương thức mở rộng cho IEnumerable<T>Linq, phiên bản .NET mới hơn. Tôi không thể chắc chắn rằng nếu Linq tồn tại với phiên bản 2.0 Findsẽ không bao giờ được thêm vào, nhưng đó có thể là trường hợp đối với nhiều tính năng khác có trong các phiên bản .NET trước đó đã bị lỗi thời hoặc dư thừa bởi các phiên bản sau.


85
Chỉ để bổ sung: Không cần phải gọi Where và First hay FirstOrDefault: First hoặc FirstOrDefault cho phép bạn chỉ định một vị từ tìm kiếm, làm cho cuộc gọi Where không cần thiết
Robson Rocha

4
Nhưng Where(condition).FirstOrDefault()tối ưu hóa ít nhất là tốt và đôi khi tốt hơn so với FirstOrDefault(condition)một mình. Chúng tôi luôn sử dụng Where()để có được hiệu suất được cải thiện khi có sẵn.
Suncat2000

7
@ Suncat2000 cung cấp một ví dụ xin vui lòng
Konstantin Salavatov

2
@ Suncat2000 Bạn đang sử dụng Linq vì sức mạnh biểu cảm của nó và muốn viết mã khai báo. Bạn không nên quan tâm đến những cải tiến vi mô như vậy, điều này cũng có thể thay đổi trong việc triển khai trong tương lai. Ngoài ra, đừng tối ưu hóa quá sớm
Piotr Falkowski

50

Tôi mới phát hiện ra hôm nay, thực hiện một số thử nghiệm trên danh sách các đối tượng 80K và thấy rằng Find()có thể nhanh hơn 1000% so với sử dụng Wherevới FirstOrDefault(). Tôi đã không biết rằng cho đến khi thử nghiệm một bộ đếm thời gian trước và sau tất cả. Đôi khi nó là cùng một lúc, nếu không thì nhanh hơn.


6
Bạn đã thử nó với Where VÀ FirstOrDefault chưa? Nếu bạn có thể đã thử nó chỉ với FirstOrDefault và xem liệu Find () có còn tốt hơn không.
MVCKarl

5
Nghe có vẻ như bạn đã không cụ thể hóa kết quả bằng một .ToList()hoặc .ToArray()thực sự thực hiện truy vấn.
Andrew Morton

4
Đó là bởi vì Findsử dụng các khóa chính (do đó là các chỉ mục), trong khi đó Wherelà một truy vấn sql đơn giản
dạng

4
Kể từ EF6, Find và FirstOrDefault đều tạo chính xác các câu lệnh SQL giống nhau. Bạn có thể thấy SQL trong ứng dụng bảng điều khiển bằng cách thực hiện bối cảnh.Database.Log = Console.Write; Ví dụ được chọn là sử dụng "Tìm" trong bộ nhớ trong danh sách các chuỗi, không đi ngược lại với DB với các khóa chính. Có lẽ bản dịch câu lệnh của mệnh đề Tìm - bỏ qua sự cần thiết phải phân tích biểu thức lambda là lý do để cải thiện hiệu suất trong trường hợp này. Chống lại cơ sở dữ liệu Tôi nghi ngờ bạn sẽ nhận thấy sự khác biệt trong các tình huống RL ... Tôi cũng tự hỏi liệu nó có được thử nghiệm bằng cách sử dụng Tìm trước thay vì thứ hai không ...
C.List

2
Chà, cải thiện hiệu suất này là do find () kiểm tra bộ đệm trong đối tượng trước khi nhấn DB trong khi đó () luôn luôn đi DB để lấy đối tượng
Gaurav

35

Có một sự khác biệt rất quan trọng nếu nguồn dữ liệu là Entity Framework: Findsẽ tìm thấy các thực thể ở trạng thái 'được thêm' chưa được duy trì, nhưng Wheresẽ không. Đây là do thiết kế.



1

ngoài câu trả lời của Anthony, Where()hãy truy cập tất cả các bản ghi và sau đó trả về (các) kết quả trong khi Find()không cần duyệt qua tất cả các bản ghi nếu vị từ khớp với vị từ đã cho.

vì vậy, nói rằng bạn có Danh sách các lớp idnamethuộc tính.

 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);

Sẽ cung cấp đầu ra 2và chỉ cần 2 lượt truy cập Tìm kiếm để đưa ra kết quả, nhưng nếu bạn sử dụng, Where().FirstOrDefault()chúng tôi sẽ truy cập tất cả các hồ sơ và sau đó chúng tôi nhận được kết quả.

Vì vậy, khi bạn biết bạn chỉ muốn kết quả đầu tiên từ hồ sơ trong bộ sưu tập Find()sẽ phù hợp hơn sau đóWhere().FirtorDefault();


4
nhưng nếu bạn sử dụng Where (). FirstOrDefault () chúng tôi sẽ truy cập tất cả các bản ghi và sau đó chúng tôi nhận được kết quả. Không. FirstOrDefaultsẽ 'bong bóng' chuỗi và ngừng liệt kê mọi thứ. Tôi sử dụng thuật ngữ 'bong bóng' vì thiếu biểu thức tốt hơn, bởi vì thực sự mọi bộ chọn / vị từ sẽ được chuyển sang tiếp theo, vì vậy phương thức cuối cùng trong chuỗi thực sự là hoạt động trước tiên.
Silvermind

1

Wow tôi chỉ xem hướng dẫn của EF từ microsofToolbox hôm nay trên Youtube. Anh ta đã nói về việc sử dụng Find () và FirstOrDefault (condition) trong truy vấn và Find () sẽ tìm kiếm dữ liệu bạn đã thực hiện một cái gì đó trên đối tượng đó (thêm hoặc chỉnh sửa hoặc xóa - nhưng chưa được lưu vào cơ sở dữ liệu) trong khi đó FirstOrDefault sẽ chỉ tìm kiếm những gì đã được lưu


-1

Find()là tương đương IEn Countable của a FirstOrDefault(). Bạn không nên xâu chuỗi cả .Where () với .FirstOrDefault().Where()đi qua toàn bộ mảng và sau đó sẽ lặp qua danh sách đó để tìm mục đầu tiên. Bạn tiết kiệm một lượng thời gian đáng kinh ngạc bằng cách đặt vị từ tìm kiếm của bạn vào FirstOrDefault()phương thức.

Ngoài ra, tôi khuyến khích bạn đọc câu hỏi được liên kết với chủ đề này để biết thêm về hiệu suất tốt hơn khi sử dụng .Find()trong các tình huống cụ thể Hiệu suất của Tìm () so với FirstOrDefault ()


Đây là một bản sao của câu trả lời ở trên của bạn. Ngoài ra, hãy xem nhận xét của Silvermind về câu trả lời đó.
carlin.scott
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.