2009-05-22 24 views
5

Tôi hiện đang sử dụng mã sau đây để đạt được điều này, nhưng có vẻ như sẽ có điều gì đó tốt hơn ... đề xuất? Nó chỉ có vẻ tôi cần có một cách để bỏ qua foreach ...Khi sử dụng mệnh đề LINQ Where trên một từ điển, làm thế nào tôi có thể trả về một từ điển cùng loại?

Dictionary<string,string> getValidIds(Dictionary<string,string> SalesPersons,List<string> ids) 
{ 
    Dictionary<string,string> o = new Dictionary<string,string>(); 
    var ie = SalesPersons.Where<KeyValuePair<string, string>>(t => ids.Contains(t.Key)); 
    foreach (var i in ie) 
    { 
     o.Add(i.Key, i.Value); 
    } 
    return o; 
} 

Trả lời

5

Có vẻ là rất nhiều nhặng xị về tìm kiếm những thứ trong danh sách. Nếu danh sách chỉ chứa một vài yếu tố, thì không có vấn đề gì lớn. Nếu Danh sách chứa hàng ngàn phần tử, bạn sẽ muốn O (1) tra cứu vào nó. HashSet có thể cung cấp điều này.

Dictionary<string, string> getValidIds(
    Dictionary<string, string> SalesPersons, 
    List<string> ids 
) 
{ 
    HashSet<string> idsFast = new HashSet<string>(ids); 
    Dictionary<string, string> result = SalesPersons 
    .Where(kvp => idsFast.Contains(kvp.Key)) 
    .ToDictionary(kvp => kvp.Key, kvp => kvp.Value) 
    return result; 
} 
9

Đẹp, chắc chắn bạn chỉ có thể gọi ToDictionary vào kết quả của cuộc gọi ở đâu:

Dictionary<string, string> GetValidIds(Dictionary<string, string> salesPersons, 
    IList<string> ids) 
{ 
    return salesPersons 
     .Where(p => ids.Contains(p.Key)) 
     .ToDictionary(p => p.Key, p => p.Value); 
} 
+0

Xem trả lời của tôi cho các ghi chú hiệu suất ... –

+0

+1, Marc, mặc dù tôi nghĩ nếu bạn lo lắng về điều này, bạn đã có quá nhiều thứ trong bộ nhớ vì nó! :) –

+1

@Matt ... tốt, có thể - nhưng có một điểm mà O (1)/O (N * log (N)) * không phải là * không hợp lý, nhưng O (N^2) * là * a vấn đề - cho dù đó là 1k, 10k hoặc 100k là tùy thuộc vào quy trình cụ thể, tất nhiên. –

6

Điều thú vị là, nếu bạn liệt kê trên từ điển (chiều dài N) đầu tiên và kiểm tra danh sách (chiều dài M) để đưa vào, sau đó bạn nhận được hiệu suất O (NM).

Bạn có thể tạo HashSet<> trong số các id nhưng điều đó có vẻ dư thừa vì chúng tôi đã có sẵn từ điển (được băm trước).

Thay vào đó, tôi sẽ lặp lại các id trước; vì tra cứu từ điển (bằng phím) là O (1), điều này mang lại hiệu suất O (M) - tuy nhiên, điều này có nghĩa là bạn không sử dụng LINQ (vì TryGetValue sẽ không yêu LINQ (và giới thiệu một tuple là quá nhiều như công việc khó khăn) ...

Dictionary<string, string> getValidIds(
      IDictionary<string, string> salesPersons, 
      IEnumerable<string> ids) { 
     var result = new Dictionary<string, string>(); 
     string value; 
     foreach (string key in ids) { 
      if (salesPersons.TryGetValue(key, out value)) { 
       result.Add(key, value); 
      } 
     } 
     return result; 
    } 

nó không quá quan tâm tôi rằng đây là dòng hơn so với phiên bản LINQ, nó loại bỏ một O (N) phức tạp ...


Chỉnh sửa, sau đây có thể công việc (tôi đã không thử nghiệm nó), nhưng tôi nghĩ rằng nó là một lạm dụng LINQ, và chắc chắn sẽ không quy mô để PLINQ vv ... sử dụng hết sức thận trọng !! Tôi cũng tin cách tiếp cận đơn giản foreach có các chi phí ít hơn, như vậy sẽ nhanh hơn ... anyway:

Dictionary<string, string> getValidIds(
     IDictionary<string, string> salesPersons, 
     IEnumerable<string> ids) 
    { 
     string value = null; 
     return (from key in ids 
       where salesPersons.TryGetValue(key, out value) // HACK: v. dodgy 
       select new { key, value }) 
       .ToDictionary(x=>x.key, x=>x.value); 
    } 
Các vấn đề liên quan