2009-07-27 21 views
5

Tôi hiện đang có một menu với subitems đang được lưu trữ trong biến từ điển này:Có bộ sưu tập <string, object> từ điển nào cho phép nhiều khóa không?

private Dictionary<string, UserControl> _leftSubMenuItems 
    = new Dictionary<string, UserControl>(); 

Vì vậy, tôi thêm quan điểm cho ví dụ các "khách hàng" phần như thế này:

_leftSubMenuItems.Add("customers", container.Resolve<EditCustomer>()); 
_leftSubMenuItems.Add("customers", container.Resolve<CustomerReports>()); 

Nhưng kể từ khi tôi đang sử dụng một từ điển, tôi chỉ có thể có một khóa có tên "khách hàng".

xu hướng tự nhiên của tôi sẽ được đến nay tạo ra một cấu trúc tùy chỉnh với thuộc tính "Mục" và "Chế độ xem", nhưng là có một bộ sưu tập NET là phù hợp hơn cho nhiệm vụ này, một cái gì đó giống như một "MultiKeyDictionary"?

ĐÁP:

Cảm ơn maciejkow, tôi mở rộng đề xuất của bạn để có được chính xác những gì tôi cần:

using System; 
using System.Collections.Generic; 

namespace TestMultiValueDictionary 
{ 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      MultiValueDictionary<string, object> leftSubMenuItems = new MultiValueDictionary<string, object>(); 

      leftSubMenuItems.Add("customers", "customers-view1"); 
      leftSubMenuItems.Add("customers", "customers-view2"); 
      leftSubMenuItems.Add("customers", "customers-view3"); 
      leftSubMenuItems.Add("employees", "employees-view1"); 
      leftSubMenuItems.Add("employees", "employees-view2"); 

      foreach (var leftSubMenuItem in leftSubMenuItems.GetValues("customers")) 
      { 
       Console.WriteLine(leftSubMenuItem); 
      } 

      Console.WriteLine("---"); 

      foreach (var leftSubMenuItem in leftSubMenuItems.GetAllValues()) 
      { 
       Console.WriteLine(leftSubMenuItem); 
      } 

      Console.ReadLine(); 
     } 
    } 

    public class MultiValueDictionary<TKey, TValue> : Dictionary<TKey, List<TValue>> 
    { 

     public void Add(TKey key, TValue value) 
     { 
      if (!ContainsKey(key)) 
       Add(key, new List<TValue>()); 
      this[key].Add(value); 
     } 

     public List<TValue> GetValues(TKey key) 
     { 
      return this[key]; 
     } 

     public List<TValue> GetAllValues() 
     { 
      List<TValue> list = new List<TValue>(); 

      foreach (TKey key in this.Keys) 
      { 
       List<TValue> values = this.GetValues(key); 
       list.AddRange(values); 
      } 

      return list; 
     } 
    } 

} 

Trả lời 2:

Cảm ơn Blixt for the tip về năng suất, đây là GetAllValues với thay đổi đó:

public IEnumerable<TValue> GetAllValues() 
{ 
    foreach (TKey key in this.Keys) 
    { 
     List<TValue> values = this.GetValuesForKey(key); 
     foreach (var value in values) 
     { 
      yield return value; 
     } 
    } 
} 

Trả lời 2 lại yếu tố nữa:

Dưới đây là một cách rất gọn gàng hơn để làm điều tương tự, nhờ Keith:

public IEnumerable<TValue> GetAllValues() 
{ 
    foreach (var keyValPair in this) 
     foreach (var val in keyValPair.Value) 
      yield return val; 
} 
+1

Đối với phương thức 'GetAllValues', bạn có thể sử dụng từ khóa' yield' thay vì tạo danh sách mới, sử dụng nhiều bộ nhớ hơn và kém hiệu quả hơn. – Blixt

+0

Đó có thể là tất cả những gì bạn cần, nhưng nó hầu như không phải là một MultiDictionary hoàn chỉnh. Điều gì về 'Remove'? Liệt kê các giá trị? vv. –

+1

Thực tế, giải pháp thích hợp ở đây là không phát minh lại bánh xe và sử dụng một trong các thư viện được liên kết trong các câu trả lời hoặc tìm kiếm một thư viện khác làm nhiều hơn những gì bạn cần. Đối với một mục đích chung như vậy, bạn chắc chắn sẽ tìm được một ứng dụng được kiểm tra và tối ưu hóa tốt. – Blixt

Trả lời

10

Nếu bạn cần số lượng giá trị thay đổi cho một khóa, tại sao không tạo Dictionary<string, List<UserControl>>? Hơn nữa, bạn có thể kế thừa lớp này và tạo Add của riêng bạn, nhận cú pháp tương tự bạn đang sử dụng ngay bây giờ.Bằng cách này, bạn có thể tránh thêm các danh sách trống theo cách thủ công trước khi thêm điều khiển mới.

sth như thế này:

class MultiValueDictionary<TKey, TValue> : Dictionary<TKey, List<TValue>> 
{ 

    public void Add(TKey key, TValue value) 
    { 
     if(!ContainsKey(key)) 
     Add(key, new List<TValue>()); 
     this[key].Add(value); 
    } 
} 
+0

Có một tài liệu được gỡ lỗi được tham chiếu tại http://stackoverflow.com/questions/1187219/is-there-a-dictionarystring-object-collection-which-allows-multiple-keys/1187252#1187252? –

1

Không, được xây dựng-in không tốt bộ sưu tập. Tôi nghĩ rằng "xu hướng tự nhiên" của bạn là hoàn toàn phù hợp để giải quyết vấn đề này, vì chúng không thực sự là "cùng một khóa", nhưng các khóa duy nhất bao gồm các phần khác nhau và Dictionary thực hiện công việc. Bạn cũng có thể lồng từ điển (có ý nghĩa nếu bạn có số lượng lớn giá trị cho mỗi tên):

Dictionary<string, Dictionary<Type, object>> dict = ...; 
var value = (T)dict[name][typeof(T)]; 

Cách tiếp cận này sẽ giải quyết thành phần sử dụng tra cứu bảng băm đơn. Nếu bạn duy trì một danh sách các mục cho mỗi phần tử, bạn sẽ phải định tuyến thẳng danh sách mỗi khi bạn cần một phần tử để tra cứu nhằm đánh bại mục đích sử dụng một Dictionary ngay từ đầu.

0

Tôi không biết "MultiKeyDictionary". Tôi khuyên bạn nên sử dụng cấu trúc và ghi đè GetHashCode, Bằng và triển khai IEquatable < StructName> (được sử dụng bởi Từ điển < TKey, TValue>).

4

Làm thế nào về việc giá trị chứa gõ một danh sách:

private Dictionary<string, List<UserControl>> _leftSubMenuItems = 
    new Dictionary<string, List<UserControl>>(); 

if (!_leftSubMenuItems.ContainsKey("customers")) 
{ 
    _leftSubMenuItems["customers"] = new List<UserControl>(); 
} 
_leftSubMenuItems["customers"].Add(container.Resolve<EditCustomer>()); 
_leftSubMenuItems["customers"].Add(container.Resolve<CustomerReports>()); 
5

Check-out NGenerics 'HashList. Đó là một từ điển duy trì một danh sách các giá trị cho mỗi khóa. Thư viện Wintellect's PowerCollections cũng có lớp MultiDictionary tiện dụng, thực hiện những việc như tự động dọn dẹp khi bạn xóa giá trị cuối cùng được liên kết với một khóa đã cho.

+0

+1: Trình bao bọc cho phép một cách tự nhiên hơn để làm những gì tôi đề xuất. – Blixt

0

Bạn đang tìm kiếm để lưu trữ nhiều mục cho mỗi khoá với nhau? Giống như this?

3

Chỉ cần một vài điều chỉnh ...

public class MultiValueDictionary<TKey, TValue> : 
    Dictionary<TKey, List<TValue>> 
{ 

    public void Add(TKey key, TValue value) 
    { 
     List<TValue> valList; 
     //a single TryGetValue is quicker than Contains then [] 
     if (this.TryGetValue(key, out valList)) 
      valList.Add(value); 
     else 
      this.Add(key, new List<TValue> { value }); 
    } 

    //this can be simplified using yield 
    public IEnumerable<TValue> GetAllValues() 
    { 
     //dictionaries are already IEnumerable, you don't need the extra lookup 
     foreach (var keyValPair in this) 
      foreach(var val in keyValPair.Value); 
       yield return val; 
    } 
} 
+0

+1 cho 'yield', mặc dù tôi vẫn tin rằng nó đã tốn thời gian thực hiện trình bao bọc của riêng bạn khi gần như chắc chắn một số khác hoàn thành (nghĩa là tất cả các chức năng có thể mong đợi từ' MultiValueDictionary') và được nhiều người dùng thử nghiệm. – Blixt

+0

Có thể đơn giản hóa GetAllValues ​​() thành điều này: 'công khai IEnumerable GetAllValues ​​() { trả về điều này.SelectMany (keyValPair => keyValPair.Value); } ' – Kaboo

1

.NET framework 3.5 bao gồm một đặc biệt lớp LINQ Lookup.

Nó tương tự như một từ điển ngoại trừ việc nó có thể xử lý nhiều mục bằng cùng một khóa. Khi bạn thực hiện tìm kiếm bằng một khóa đã cho, thay vì nhận một phần tử, bạn sẽ nhận được một nhóm các phần tử khớp với khóa đó.

Tôi đọc rằng đó là một hashtable dưới nắp vì vậy nó là nhanh chóng để lấy.

Bạn sử dụng nó một cái gì đó như thế này:

var example1 = (from element in ListWithDuplicates 
      select element) 
      .ToLookup(A => A.Name); 

Có một bó số khó khăn:

  • Lớp Lookup không có constructor nào, vì vậy bạn không thể chỉ cần tạo một đối tượng Lookup, có vẻ như chỉ có sẵn bằng cú pháp .ToLookup.
  • Bạn không thể chỉnh sửa nó khi nó đã được tạo ra, không có Add or Remove, vv
  • Rõ ràng nó không serializable
  • Sử dụng dữ liệu được nhóm có thể là một chút khôn lanh

Theres một great article here thảo luận về Lookup và ý nghĩa của nó chi tiết hơn.

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