代码之家  ›  专栏  ›  技术社区  ›  Edward Tanguay

是否存在允许多个键的字典<string,object>collection?

  •  5
  • Edward Tanguay  · 技术社区  · 16 年前

    我当前有一个菜单,其中包含存储在此字典变量中的子项:

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

    因此,我向“客户”部分添加如下视图:

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

    但是因为我在用字典, 我只能有一把名为“客户”的钥匙 .

    我的自然倾向是 自定义结构 具有属性“section”和“view”,但是 有没有一个.NET集合更适合这个任务,比如“multikeydictionary”?

    答:

    感谢麦基考,我扩大了你的建议,以得到我所需要的:

    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;
            }
        }
    
    }
    

    答案2:

    感谢blixt提供有关yield的提示,下面是getAllValues的更改:

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

    答案2进一步重构:

    这里有一个更简洁的方法来做同样的事情,谢谢基思:

    public IEnumerable<TValue> GetAllValues()
    {
        foreach (var keyValPair in this)
            foreach (var val in keyValPair.Value)
                yield return val;
    }
    
    8 回复  |  直到 16 年前
        1
  •  10
  •   Jamie Ide    16 年前

    如果一个键需要可变数量的值,为什么不创建 Dictionary<string, List<UserControl>> ?此外,您可以继承这个类并创建自己的add,获得现在使用的相同语法。这样可以避免在添加新控件之前手动添加空列表。

    像这样的东西:

    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);
       }
    }
    
        2
  •  5
  •   Matt Howells    16 年前

    退房 NGenerics HashList . 这是一个字典,它维护每个键的值列表。 Wintellect's PowerCollections 库还有一个方便的多部门类,它可以在删除与给定键关联的最后一个值时自动清理。

        3
  •  4
  •   Blixt    16 年前

    如何使容器值类型为列表:

    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>());
    
        4
  •  3
  •   Keith    16 年前

    只是一些小改动…

    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;
        }
    }
    
        5
  •  2
  •   TripleAntigen    12 年前

    .NET Framework 3.5包含一个特殊的LINQ Lookup 班级。

    它与字典类似,只是它可以用同一个键处理多个项。当您使用给定的键进行搜索,而不是接收单个元素时,您将接收一组与该键匹配的元素。

    我读到它是一个封面下的哈希表,所以检索速度很快。

    你可以这样使用它:

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

    有一堆警告:

    • lookup类没有公共构造函数,因此您不能只创建一个lookup对象,它似乎只能使用.to lookup语法。
    • 创建后不能编辑,不能添加或删除等。
    • 显然它不可序列化
    • 使用分组数据可能有点困难

    有一个 great article here 更详细地讨论查找及其含义。

        6
  •  1
  •   Mehrdad Afshari    16 年前

    不,没有更好的内置收藏。我认为你的“自然倾向”非常适合解决这个问题,因为它们不是真正的“同一把钥匙”,而是由不同部分和 Dictionary 做这项工作。您还可以嵌套字典(如果每个名称有大量值,则有意义):

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

    此方法将使用单个哈希表查找解析元素。如果为每个元素维护一个项目列表,则每次需要查找一个元素时,都必须线性遍历该列表,这会破坏使用 词典 首先。

        7
  •  0
  •   Richard Szalay    16 年前

    我不知道有什么“多键字典”。我建议使用结构并重写gethashcode、equals并实现IEquatable<structname>(字典<tkey、tvalue>使用)。

        8
  •  0
  •   Community CDub    8 年前

    您是否希望将每个键的多个条目存储在一起?有点像 this ?