Việc sử dụng .Any () trong Danh sách C # <> là gì?


40

Tôi đã thảo luận vấn đề này với các đồng nghiệp và chúng tôi không thể tìm ra cách sử dụng .Anycho bất kỳ mục đích nào List<>, trong C #.

Bạn có thể kiểm tra tính hợp lệ của một phần tử trong mảng như câu lệnh sau:

if (MyList.Any()){ ...}  //Returns true or false

Mà giống hệt như

if (MyList.Count() != 0) { ... }

và là phổ biến hơn nhiều, có thể đọc và rõ ràng về ý định của iftuyên bố.

Cuối cùng, chúng tôi bị mắc kẹt với suy nghĩ này:

.Any() có thể được sử dụng, sẽ hoạt động tốt, nhưng không rõ ràng về ý định của lập trình viên, và trường hợp đó không nên sử dụng.

Nhưng chúng tôi cảm thấy như thế này không thể đúng; chúng ta phải thiếu một cái gì đó

Có phải chúng ta không?


40
theo cách nào là ít rõ ràng hơn về ý định?
jk.

35
Tôi thách thức yêu cầu của bạn Any()chưa rõ ràng: Any()dường như rõ ràng hơn đối với tôi, đặc biệt là với tình trạng lambda. Dịch mã sang tiếng Anh trong đầu tôi, if(MyList.Count(o => o > 10) > 0)trở thành "Số lượng vật phẩm có lớn hơn 10 hơn 0 không?" trong khi if(MyList.Any(o => o > 10))trở thành "Có mục nào lớn hơn 10 không?"
BlueRaja - Daniel Pflughoeft

3
@SargeBorsch - chỉ khi bạn thích đặt tên Heskel / chức năng, mà hầu hết mọi người không làm.
Davor Ždralo

4
@ BlueRaja-DannyPflughoeft tôi đồng ý. Tôi nghĩ bất kỳ điều gì rõ ràng hơn vì nó loại bỏ một thứ có thể được coi là một con số ma thuật.
Andy

2
@SargeBorsch: SQL song song AnyExists. Tên Linq có lẽ được lấy cảm hứng nhiều hơn bởi Haskell và Python cũng có bất kỳ / tất cả các chức năng.
JacquesB

Câu trả lời:


95

Hãy nhớ rằng Anykhông hoạt động trên một List; nó hoạt động trên một IEnumerable, đại diện cho một loại cụ thể có thể có hoặc không có Counttài sản. Đúng là nó không nhất thiết phải là thứ tốt nhất để sử dụng trên một List, nhưng nó chắc chắn có ích khi kết thúc truy vấn LINQ. Và thậm chí hữu ích hơn phiên bản độc lập là ghi đè có một vị ngữ giống như Where. Không có gì được xây dựng trên Listbất cứ nơi nào gần thuận tiện hoặc biểu cảm như Anyphương pháp mở rộng vị ngữ .

Ngoài ra, nếu bạn đang sử dụng Count()(phương thức mở rộng LINQ cho IEnumerable), thay vì Count(thuộc tính trên List), nó có thể phải liệt kê toàn bộ chuỗi nếu không thể tối ưu hóa điều này bằng cách phát hiện loại dữ liệu cơ bản của bạn có CountThuộc tính . Nếu bạn có một chuỗi dài, đây có thể là một hiệu suất đáng chú ý khi bạn không thực sự quan tâm đến số đếm là gì và chỉ muốn biết liệu có bất kỳ mục nào trong bộ sưu tập không.


19
Điều này. Hiệu suất sang một bên, Any()với một vị là nhiều biểu cảm hơn so sánh các ghi đè Enumerable.Count()mà phải mất một vị ngữ với 0. :)
Dan J

1
Tôi nghĩ rằng điều này giải thích các nguyên tắc cơ bản rõ ràng để giải thích câu trả lời tốt nhất.
Tarik

2
IMHO, Existschỉ là thuận tiện và biểu cảm như Any, với một vị ngữ. Sử dụng Count != 0tài sản trên a Listlà bình thường hơn so với sử dụng Any(). Đó chỉ là sở thích cá nhân. Tôi cũng trải qua những nỗ lực thay đổi _list_.Count()để _list_.Counttrong mã nhóm của tôi. Nó làm cho một sự khác biệt đáng chú ý với tôi.
Suncat2000

55

Có một sự khác biệt về thời gian chạy Count()có thể là O (n) trong đó Any()O (1).


15
Count()cũng sẽ không dừng lại cho các trình vòng lặp vô hạn, trong khi Any()sẽ, vì nó chỉ cần gọi MoveNext()một lần.
Jon Purdy

3
Cô đọng và chính xác, nhưng điều này đọc nhiều hơn là một nhận xét hơn là một câu trả lời. Các lập trình viên thích các câu trả lời đi sâu vào lý do tại sao và đưa ra một biện pháp giải thích. Xem xét chỉnh sửa câu trả lời của bạn và mở rộng lý do tại sao O (1) có thể (là) quan trọng.

câu trả lời rất hay vừa học tôi nên sử dụng bất kỳ thay vì đếm == 0: d
MonsterMMORPG

4
Any(Func<T>)là O (n)
BlueRaja - Daniel Pflughoeft

1
Trong trường hợp cụ thể List, hiệu suất là như nhau vì tiện ích mở rộng sử dụng thuộc tính. Đúng cho tất cả các bộ sưu tập thực hiện ICollectiongiao diện.
Thorkil Holm-Jacobsen

9

Trên thực tế, hãy nhớ rằng có thuộc tính List.Count , và sau đó có phương thức Enumerable.Count .

Trong ví dụ của bạn, bạn đang sử dụng Enumerable.Count()phương thức, phải lặp lại qua từng mục của bảng liệt kê để trả về kết quả. Đó rõ ràng là chậm hơn so với việc gọi Any()vốn chỉ cần lặp lại qua mục đầu tiên, nếu nó tồn tại.

CHỈNH SỬA:

Trong các bình luận, nó đã được chỉ ra, đúng như vậy, Enumerable.Count()phương thức mở rộng đó không cần phải lặp đi lặp lại qua tất cả các mục nếu nó phát hiện ra rằng vô số cũng xảy ra là một ICollection<T>. Vì vậy, trong trường hợp a List<T>, sử dụng thuộc Counttính hoặc phương thức không thực sự tạo ra sự khác biệt.

IEnumerable.Count nguồn:

public static int Count<TSource>(this IEnumerable<TSource> source) {
    if (source == null) throw Error.ArgumentNull("source");
    ICollection<TSource> collectionoft = source as ICollection<TSource>;
    if (collectionoft != null) return collectionoft.Count;
    ICollection collection = source as ICollection;
    if (collection != null) return collection.Count;
    int count = 0;
    using (IEnumerator<TSource> e = source.GetEnumerator()) {
        checked {
            while (e.MoveNext()) count++;
        }
    }
    return count;
}

Đủ công bằng. Thế còn việc sử dụng tài sản .Count thì sao? điều đó sẽ làm cho việc đọc nhanh hơn đáng kể, có thể nhanh hơn hoặc thậm chí nhanh hơn so với việc gọi .Any ()?
Gil Sand

4
Với List<T>sự khác biệt hiệu suất sẽ không đáng kể. Vì vậy, chỉ cần sử dụng những gì bạn thích. Nhưng đối với các loại IEnumerables khác, bạn chỉ có thể chọn giữa Count()(phương thức) và Any(), trong trường hợp đó, Any()sẽ luôn là người chiến thắng rõ ràng cho trường hợp sử dụng của bạn và nên được ưu tiên. Đối với những gì nó có giá trị, tôi nghĩ Any()là khá dễ đọc và rõ ràng.
sstan

@sstan có trừ khi nếu ienumerable có thể được chuyển sang một bộ sưu tập thì nó có thể được tối ưu hóa và nó sẽ không thành vấn đề.
Esben Skov Pedersen

2
Count()có độ phức tạp tương tự như Countđối với ICollections, vì phương thức mở rộng sau đó sử dụng thuộc tính thay vì lặp.
Thorkil Holm-Jacobsen

Các phần mở rộng Linq được tối ưu hóa cho các giao diện đã biết - IList, ICollection. Thảo luận về hiệu suất ở đây là hoàn toàn dư thừa, ngay cả khi đó là chi tiết triển khai
Gusdor

6

Một câu hỏi đáng ngạc nhiên - tôi thấy mục đích của list.Any()nó rõ ràng hơn nhiều so với ý định list.Count()!=0.

Ý định có nghĩa là: Nếu bạn đọc mã của ai đó (và bạn không tự viết nó), thì việc lập trình viên muốn đạt được là gì và tại sao nó lại được viết như vậy? Nếu một vấn đề phổ biến được giải quyết theo cách phức tạp không cần thiết, bạn sẽ ngay lập tức nghi ngờ và tự hỏi tại sao nhà phát triển không sử dụng cách đơn giản. Bạn xem qua mã và thử xem bạn có bỏ sót điều gì không. Bạn sợ thay đổi mã bởi vì bạn lo lắng có một số tác dụng phụ bạn đang thiếu và thay đổi nó có thể gây ra sự cố không mong muốn.

Ý định sử dụng Any()phương pháp này hoàn toàn rõ ràng - bạn muốn biết liệu có bất kỳ yếu tố nào trong danh sách hay không.

Mặt khác, ý định của biểu thức Count()!=0không rõ ràng đối với người đọc. Tất nhiên không khó để thấy rằng biểu thức cho bạn biết nếu danh sách trống hay không. Các câu hỏi phát sinh bởi vì bạn viết nó theo cách đặc biệt này hơn là sử dụng phương pháp tiêu chuẩn. Tại sao bạn sử dụng Count()rõ ràng? Nếu bạn thực sự chỉ cần biết nếu có bất kỳ yếu tố nào trong danh sách, tại sao bạn muốn đếm toàn bộ danh sách trước? Ngay khi bạn đạt 1, bạn đã có câu trả lời của mình. Nếu nguồn là một trình vòng lặp trên một bộ sưu tập lớn (có thể là vô hạn) hoặc được dịch sang sql, thì nó có thể tạo ra sự khác biệt lớn về hiệu suất. Vì vậy, có thể việc sử dụng rõ ràng của Count () là để buộc một truy vấn bị trì hoãn thực thi hoặc để duyệt qua một trình vòng lặp?

Nhưng nguồn thực sự là một List<T>nơi Count()là O (1) và không có tác dụng phụ. Nhưng nếu mã dựa vào thuộc tính này List<T>, thì tại sao không sử dụng Count-property mà chỉ rõ hơn rằng bạn mong đợi một hoạt động O (1) không có tác dụng phụ?

Như nó được viết, list.Count()!=0thực hiện chính xác giống như list.Any()ngoại trừ nó phức tạp hơn không cần thiết và ý định không rõ ràng.


Tôi đọc cả hai như, "danh sách có chứa mục nào không?" Count()có một chuyển đổi ngụ ý mà tôi sẽ tránh sử dụng, nhưng nó không rõ ràng. Trình biên dịch có thể tối ưu hóa nó đi, điều này chỉ làm cho nó bất cẩn mã hóa.
Suncat2000

2

Có lẽ đó chỉ là từ? Anylà một tính từ, không thực sự nói bất cứ điều gì. Đến từ Java, tôi gọi nó isNonEmptylà một động từ. Một anh chàng SQL có thể thích EXISTS. Nhưng có lẽ Anyphù hợp nhất trong hệ thống C #.

Dù lựa chọn từ nào, một khi bạn đã quen với nó, nó phải rõ ràng hơn. Bạn có hỏi "Có more than zerochai bia nào còn lại không". Bạn có mong đợi one or morenhững người bắt đầu đếm họ trước khi họ trả lời "Không, không có any"?


1
Cái tên "bất kỳ" có ý nghĩa khi bạn nghĩ về nó theo thuật ngữ LINQ: Any()thực sự là một lối tắt choAny(o => true)
BlueRaja - Danny Pflughoeft

Tôi thường sẽ không sử dụng sản phẩm nào để mô tả nếu một vô số có bất kỳ điều gì để liệt kê. Nhưng "có bất cứ điều gì để liệt kê" có vẻ tự nhiên đối với tôi, và Bất kỳ công việc nào chống lại bất kỳ sự liệt kê nào.
Andy
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.