【问题标题】:Multi-key dictionary with optional keys带有可选键的多键字典
【发布时间】:2011-08-25 23:39:57
【问题描述】:

我需要一个包含 2 种不同类型(int 和 string,都是唯一的,因此它们只能出现在 1 个键内)的多个键的字典。下面是一个例子:组信息(GroupInfo)可以通过 GroupdId 或其中一个成员名称来查询:


GroupId   MemberNames           GroupInfo
{1,       John, Mary, Joe} ==>  {GroupInfo}

因此,当 id (1) 或成员名称之一 (John) 请求时,应返回组信息。

我的第一个解决方案是创建一个包含 GroupdId 和 MemberNames 的密钥,该方法使用覆盖的 Equals 方法比较 GroupIds 并查找成员列表。但是要使这些条目相等:


GroupId   MemberNames          
{0,       John}
{1,       null}
{1,       Mary}

GetHashCode 必须返回相同的 const 值。这将导致字典成为链表,并且在最佳情况下性能下降到 O(N) 查找。

另一种解决方案是分别保留 2 个字典:GroupId ==> GroupInfo、MemberName ==> GroupInfo。

还有其他想法吗?

【问题讨论】:

  • 能否将 GroupId 转换为字符串,以便使用单个字典?
  • 您反对只使用这两个字典的原因是什么?这很简单,显然是正确的。
  • @Philipp +1 提供了一个我没想过的好解决方案。可以,但是您如何通过键删除?例如,给定一个键“John”,所有其他键也应该被删除。
  • 我不知道字典查找是否允许这样做,但你能定义自定义比较器吗?一个查看id,一个查看MemberName
  • @Philipp,我决定听从您的建议,使 GroupId 成为字典中的键之一(ID 和成员之间不会发生冲突)并使值保持反向引用键,这样如果一个被删除,其余的将被删除。您能否将您的评论转换为答案,以便我接受?

标签: c# .net-3.5 dictionary hashtable


【解决方案1】:

根据您在评论中描述的内容

你是如何通过按键删除的?例如,给定一个键“John”,所有其他键也应该被删除。

现在您可能已经清楚,“字典”不是您想要的。主要是因为您需要多种键类型,并且需要将键映射到其他键。

因此您可以创建自己的实现 IDictionary 的类。基本上如下。

    class MultiKeyDictionary : IDictionary
{
    Dictionary<string, GroupInfo> stringDict = new Dictionary<string, GroupInfo>();
    Dictionary<int, GroupInfo> intDict = new Dictionary<int, GroupInfo>();
    Dictionary<GroupInfo, List<object>> keysDict = new Dictionary<GroupInfo, List<object>>();

    //Each of these would add to their own dictionary, as well as adding the backwards
    //entry in the "keysDict"
    public void Add(string memberName, GroupInfo value);
    public void Add(int key, GroupInfo value);

    public bool Contains(string key);
    public bool Contains(int key);

    //This would be the enumerator of the "keys" of "keysDict"
    //because it is actually a list of all GroupInfos
    public IDictionaryEnumerator GetEnumerator()

    public ICollection NameKeys;
    public ICollection GroupIDKeys;
    //This is to adhere to the interface. It should be carefully commented or even deprecated.
    public ICollection Keys;

    //For this, you look up the GroupInfo for the key, then do
    //foreach(object key in keysDict[<groupInfoIJustLookedUp>]) {
    //   if(key.gettype == typeof(string) stringDict.Remove(key);
    //   else if (key.gettype == typeof(int) intDict.Remove(key);
    //   else //WHAT?!?
    //}
    public void Remove(string key);
    public void Remove(int key);

    //This would be the "Keys" collection of the "keysDict"
    public ICollection Values;

    //etc... etc...
    public object this[string memberName];
    public object this[int groupId];
}

【讨论】:

  • 那行得通,谢谢,但最终会封装我不想做的 2+ 字典
  • @kateroh 你为什么不想这样做?您创建了一个脆弱的解决方案,该解决方案依赖于您的密钥不相互重叠(适用于您的情况,但不适用于一般情况),并且维护两个字典的工作被完全抽象出来,因此对于用户/编码器应用程序,他们不需要关心。它们的界面将与以前完全相同,只是您的代码现在更适应未来。
【解决方案2】:

为了只维护 1 个字典,考虑将 GroupId (int) 转换为字符串并将其用作键(数字“键”不应与名称键冲突)。维护一个对键的引用,这样如果一个被删除,其余的都会被删除。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-09-06
    • 2021-09-01
    • 1970-01-01
    • 1970-01-01
    • 2010-11-14
    • 2011-06-05
    • 1970-01-01
    相关资源
    最近更新 更多