2010-01-02 28 views
10

Câu hỏi nhanh, cách thích hợp nhất để lập trình hỏi là "Có chính xác một phần tử trong chuỗi này thỏa mãn điều kiện X không?" sử dụng LINQ?Cách hỏi "Có chính xác một yếu tố đáp ứng điều kiện" trong LINQ không?

ví dụ:

// Pretend that the .OneAndOnlyOne() method exists 
int[] sequence = new int[] { 1, 1, 2, 3, 5, 8 }; 
Assert.IsTrue(sequence.OneAndOnlyOne(x => x == 2); 
Assert.IsFalse(sequence.OneAndOnlyOne(x => x == 1); 

một cái gì đó như thế này có thể được thực hiện với:

sequence.SingleOrDefault(x => x == 2) != null; 

nhưng đó là một chút vụng về.

Tôi cho rằng tôi có thể cuộn phương thức tiện ích của riêng mình, nhưng điều này có vẻ là một mẫu chung trong mã của tôi và tôi muốn đảm bảo có cách làm sạch tốt. Có cách nào sử dụng các phương pháp LINQ tích hợp không?

+0

'SingleOrDefault' sẽ ném một InvalidOperationException : nếu có nhiều hơn một trận đấu. – SLaks

+0

Tôi khuyên bạn nên sử dụng IsLone() làm tên thay thế cho phương pháp mở rộng. Bạn cũng đang làm 2 việc với cùng chức năng, lọc và sau đó phát hiện nếu chỉ có 1 phần tử. Tôi sẽ làm: sequence.Where (x => x == 2) .IsLone() – ICR

Trả lời

29

Bạn có thể làm:

bool onlyOne = source.Where(/*condition*/).Take(2).Count() == 1 

Mà sẽ ngăn chặn đếm từ liệt kê một chuỗi lớn không cần thiết trong trường hợp có nhiều kết quả trùng khớp.

+0

+1 và tôi ước tôi có thể cung cấp cho bạn một +1 khác cho phần '.Take (2)' (vì điều đó rất có ý nghĩa.) –

+0

heh, tôi giống như vậy. Tôi có lẽ sẽ bí danh rằng đằng sau phương pháp mở rộng của riêng tôi. – Mike

+0

Tại sao bạn lấy 2 phần tử? Ý nghĩa đằng sau điều đó là gì? ;) – citronas

2

Cách đơn giản nhất là chỉ sử dụng Count. Single sẽ không làm việc cho bạn, bởi vì nó ném một ngoại lệ nếu không chỉ có phần tử đơn lẻ đó.

LBushkin gợi ý (trong nhận xét) để sử dụng SequenceEqual để so sánh trình tự với một số khác. Bạn có thể sử dụng bằng cách bỏ qua các yếu tố đầu tiên với Skip (1), và so sánh trình tự dẫn đến một chuỗi rỗng như những gì bạn có thể nhận được từ Empty

+2

Vâng, nhưng nếu phương thức .OneAndOnlyOne() của tôi chạy trên một chuỗi và nhấn một phần tử thứ 2 thỏa mãn vị từ - nó có thể trả về false xa. Count() sẽ liệt kê toàn bộ chuỗi – Mike

+0

Điều đó đúng, nhưng việc "vượt quá" Đếm có thể là một trường hợp tối ưu hóa sớm - tùy thuộc vào nhu cầu của bạn, tất nhiên. Nếu bạn muốn ngăn chặn điều đó, bạn có thể sử dụng .Skip (1) và xem nếu bạn nhận được một chuỗi rỗng. –

+0

@Michael: Bạn không cần sử dụng Count. Bạn có thể sử dụng 'SequenceEqual()' để xử lý các chuỗi rỗng chỉ tốt mà không cần ném ngoại lệ. Và, bạn luôn có thể cuộn phương thức mở rộng của riêng mình ... không phải là nó thực sự cần thiết cho trường hợp sử dụng của OP. – LBushkin

0

Bạn có thể sử dụng phương pháp mở rộng này, mà tôi nghĩ nên đã được đưa vào các phương pháp khuyến nông chuẩn cho LINQ:

public static int CountUpTo<T>(this IEnumerable<T> sequence, int maxCount) { 
    if (sequence == null) throw new ArgumentNullException("sequence"); 
    if (maxCount < 0) throw new ArgumentOutOfRangeException("maxCount"); 

    var count = 0; 
    var enumerator = sequence.GetEnumerator(); 
    while (count < maxCount && enumerator.MoveNext()) 
     count += 1; 
    return count; 
} 

Được sử dụng như sau:

return sequence.CountUpTo(2) == 1; 
Các vấn đề liên quan