是否有Dictionary <string,object =“”>集合,它允许多个键?</string,>

时间:2009-07-27 09:12:50

标签: c# collections

我目前有一个子项目的菜单存储在这个字典变量中:

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

所以我添加了视图,例如像这样的“客户”部分:

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

但由于我使用的是词典,我只能有一个名为“customers”的键

我的自然倾向是现在创建一个带有“Section”和“View”属性的自定义结构,但是否有一个.NET集合更适合此任务,类似于一个“MultiKeyDictionary”?

解答:

感谢maciejkow,我扩展了你的建议,以获得我所需要的东西:

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 个答案:

答案 0 :(得分:10)

如果一个键需要可变数量的值,为什么不创建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);
   }
}

答案 1 :(得分:5)

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

答案 2 :(得分:4)

如何将容器值类型设为列表:

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>());

答案 3 :(得分:3)

只需进行一些调整......

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

答案 4 :(得分:2)

.NET framework 3.5包含一个特殊的LINQ Lookup类。

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

我读到它是一个哈希表,所以它很快就可以检索。

你使用这样的东西:

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

有一些警告:

  • Lookup类没有公共构造函数,所以你不能只创建一个Lookup对象,它似乎只能使用.ToLookup语法。
  • 创建后无法编辑,无添加或删除等。
  • 显然它不可序列化
  • 使用分组数据可能有点棘手

Theres a great article here更详细地讨论了Lookup及其含义。

答案 5 :(得分:1)

不,没有更好的内置系列。我认为你的“自然倾向”非常适合解决这个问题,因为那些不是真正“相同的键”,但由不同部分组成的唯一键和Dictionary完成了这项工作。您还可以嵌套字典(如果每个名称都有大量值,则有意义):

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

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

答案 6 :(得分:0)

我不知道“MultiKeyDictionary”。我建议使用结构并重写GetHashCode,Equals并实现IEquatable&lt; StructName&gt; (由Dictionary&lt; TKey,TValue&gt;使用)。

答案 7 :(得分:0)

您是否希望将每个密钥存储多个条目?类似this的内容?