2009-04-27 44 views
65

Tôi có một cuốn từ điển các loạiKiểm tra nếu KeyValuePair tồn tại với LINQ của FirstOrDefault

Dictionary<Guid,int> 

Tôi muốn trở lại trường hợp đầu tiên mà một điều kiện được đáp ứng bằng

var available = m_AvailableDict.FirstOrDefault(p => p.Value == 0) 

Tuy nhiên, làm thế nào để kiểm tra xem Tôi đang thực sự nhận được một KeyValuePair? Tôi không thể sử dụng! = Hoặc == để kiểm tra mặc định (KeyValuePair) mà không có lỗi trình biên dịch. Có một chủ đề tương tự here dường như không có giải pháp. Tôi thực sự có thể giải quyết vấn đề cụ thể của tôi bằng cách lấy chìa khóa và kiểm tra mặc định của Guid, nhưng tôi tò mò nếu có một cách tốt để làm điều này với keyvaluepair. Cảm ơn

+0

tôi thấy [câu trả lời này đến câu hỏi khác] (http://stackoverflow.com/a/7153921/945456) hữu ích. Về cơ bản sử dụng '.Where()' và sau đó sử dụng '.Any()' trên kết quả của điều đó để quyết định xem bạn có kết quả trả về hay không. –

Trả lời

89

Nếu bạn chỉ quan tâm đến sự tồn tại, bạn có thể sử dụng ContainsValue(0) hoặc Any(p => p.Value == 0) để thay thế? Tìm kiếm theo giá trị là không bình thường đối với một Dictionary<,>; nếu bạn đang tìm kiếm bằng khóa, bạn có thể sử dụng TryGetValue.

Một cách tiếp cận khác:

var record = data.Where(p => p.Value == 1) 
    .Select(p => new { Key = p.Key, Value = p.Value }) 
    .FirstOrDefault(); 

này trả về một lớp - như vậy sẽ null nếu không tìm thấy.

+5

Đó là một thủ thuật gọn gàng bằng cách sử dụng các loại ẩn danh để giả mạo làm cấu trúc. Tôi sẽ phải nhớ điều đó. –

+3

@Và họ đang giả mạo thành bộ dữ liệu hơn bất cứ thứ gì ... –

+1

Không, đó không phải là ý tôi. Tuples đơn giản hơn, do đó, nó không thực sự có ý nghĩa để nghĩ rằng các loại vô danh là "cố gắng để trông giống như tuples". Ý tưởng đằng sau nhận xét của tôi là nếu bạn sử dụng 'var', bạn có thể thay thế cấu trúc bằng một loại ẩn danh mà không cần bất kỳ sửa lỗi tham chiếu nào, như bạn đã làm ở trên. –

2

bạn có thể kiểm tra xem

available.Key==Guid.Empty 
+2

Trừ khi Guid. Rỗng là khóa có khả năng hợp lệ ... –

+0

vâng, tất nhiên. – pomarc

22

tôi đề nghị bạn thay đổi nó theo cách này:

var query = m_AvailableDict.Where(p => p.Value == 0).Take(1).ToList(); 

Sau đó bạn có thể xem danh sách là rỗng hay không, và lấy giá trị đầu tiên nếu nó không, ví dụ

if (query.Count == 0) 
{ 
    // Take action accordingly 
} 
else 
{ 
    Guid key = query[0].Key; 
    // Use the key 
} 

Lưu ý rằng không có khái niệm thực sự về mục nhập "đầu tiên" trong từ điển - thứ tự mà nó được lặp lại không được xác định rõ. Nếu bạn muốn nhận cặp khóa/giá trị là đầu tiên được nhập bằng giá trị đó, bạn sẽ cần một từ điển giữ gìn thứ tự của một loại nào đó.

(Đây là giả định bạn thực sự muốn biết phím - nếu bạn chỉ sau một kiểm tra sự tồn tại, Marc's solution là thích hợp nhất.)

+0

@Jon - để tránh sự cần thiết cho một danh sách, vv, xem cập nhật của tôi. –

9

gì bạn muốn một phương pháp Any cung cấp cho bạn các yếu tố kết hợp là cũng. Bạn có thể dễ dàng tự viết phương pháp này.

public static class IEnumerableExtensions 
{ 
    public static bool TryGetFirst<TSource>(this IEnumerable<TSource> source, 
              Func<TSource, bool> predicate, 
              out TSource first) 
    { 
    foreach (TSource item in source) 
    { 
     if (predicate(item)) 
     { 
     first = item; 
     return true; 
     } 
    } 

    first = default(TSource); 
    return false; 
    } 
} 
+0

Tôi nghĩ có lẽ tôi nên gọi thử TryGetFirst hoặc TryFirst này, với sự giống nhau của nó với TryGetValue/TryParse. –

+0

TryGetFirst khá tốt. Nhưng cuối cùng bạn có thể đặt tên nó là bất cứ điều gì bạn muốn. – Samuel

+0

(Nhưng ý tưởng hay cho phương pháp mở rộng - +1 :) –

11

Sử dụng từ khóa mặc định().

bool exists = !available.Equals(default(KeyValuePair<Guid, int>)); 
+1

Tôi nghĩ kết quả nên được đảo ngược, như: bool exist =! Available.Equals (mặc định (KeyValuePair )); – Jaime

+0

Có bạn đúng. Cảm ơn bạn! –

0

Một cách để kiểm tra so với giá trị mặc định của một struct như KeyValuePair mà không chỉ định loại là để tạo một đối tượng mới sử dụng Activator:

if (available.Equals(Activator.CreateInstance(available.GetType()))) 
{ 
    Console.WriteLine("Not Found!"); 
} 
+0

Tôi nghĩ rằng điều này có thể tương tự như câu trả lời của Florian bằng cách sử dụng từ khóa mặc định(). Cách tiếp cận của bạn có thể chậm hơn trong thời gian chạy. –

Các vấn đề liên quan