多部分 int 字典键的最佳方法?

Posted

技术标签:

【中文标题】多部分 int 字典键的最佳方法?【英文标题】:Best approach to multi-part int dictionary key? 【发布时间】:2011-06-25 20:40:04 【问题描述】:

假设我的字典需要使用 ItemId 和 RegionId 的组合作为键,两者都是 int。并说价值侧的类型是“数据”。 我可以通过以下几种方式做到这一点:

方式一:多级字典,像这样:

Dictionary<int, Dictionary<int, Data>>  myData;

所以查询可以这样编码:

Data data1  = myData[itemId][regionId];

不错,但缺点是我需要在第一级检查密钥是否存在,所以更安全的代码会是

Data data1 = null;
if (myData.ContainsKey(itemId)) data1 =  myData[itemId][regionId];

方式2:使用多部分密钥。 在这种方法中,我将创建一个结构来表示各个部分,并使用一个结构作为字典键:

private struct MultiPartKey

    public int ItemId;
    public int RegionId;


Dictionary<MultiPartKey, Data>  myData;

查找如下:

MultiPartKey mpk;
mpk.ItemId = itemId;
mpk.RegionId = regionId;
Data data1 = myData[mpk];

这里的一个可能的缺点是它仅在我的结构完全由简单值类型组成时才有效,因此两个实例的按位比较将相等。 (对吧?)

你怎么看?

【问题讨论】:

您的密钥类应覆盖 EqualsGetHashCode 以允许比较。 msdn.microsoft.com/en-us/library/kw5aaea4%28VS.80%29.aspx Tuples( or arrays ) as Dictionary keys in C# 的可能副本。 还有 is-there-a-benefit-to-tuple-based-or-nested-dictionaries 【参考方案1】:

与其让你的结构像那样“愚蠢”(和可变),你可以让它不可变并给它适当的平等方法,例如

private struct MultiPartKey : IEquatable<MultiPartKey>

    private readonly int itemId;
    private readonly int regionId;

    public int ItemId  get  return itemId;  
    public int RegionId  get  return regionId;  

    public MultiPartKey(int itemId, int regionId)
    
        this.itemId = itemId;
        this.regionId = regionId;
    

    public override int GetHashCode()
    
        int hash = 17;
        hash = hash * 31 + itemId;
        hash = hash * 31 + regionId;
        return hash;
    

    public override bool Equals(object other)
    
        return other is MultiPartKey ? Equals((MultiPartKey)other) : false;
    

    public bool Equals(MultiPartKey other)
    
        return itemId == other.itemId &&
               regionId == other.regionId;
    

您可以扩展它以使用您想要的任何类型,只要您正确实现相等和哈希码。实现IEquatable&lt;MultiPartKey&gt; 意味着字典不需要将键装箱来比较它们。

使用这种方法而不是 Dictionary&lt;int, Dictionary&lt;int, Data&gt;&gt; 的缺点是您无法轻松找到给定项目 ID 的所有条目。

【讨论】:

感谢 Jon 和其他人的回复,但在我声明的约束(只有值类型成员的结构)内,我不需要覆盖 equals 或 gethashcode 吗? .Net 值类型(例如结构)的相等性将是按位比较。 @Elroy:虽然你没有,但我个人会。除此之外,它会阻止拳击。 @Elroy:另一点是,您不会受限于简单的值类型。哦,我似乎记得默认为结构生成的哈希码只使用第一个字段,在你的情况下,这对于哈希冲突来说是非常垃圾的。 感谢IEquatable&lt;T&gt; 提示。是的,你没记错,来自ValueType.GetHashCode:“派生类型的一个或多个字段用于计算返回值。如果调用派生类型的GetHashCode方法,返回值不太可能适合用作哈希表中的一个键。” @astef:这是不可能的——因为MultiPartKey 是一个结构体。【参考方案2】:

另一种方法是使用 Tuple 类:

Dictionary<Tuple<int, int>, Data>  myData;

这适用于最多八个值,只要它们实现 EqualsGetHashCode

【讨论】:

以上是关于多部分 int 字典键的最佳方法?的主要内容,如果未能解决你的问题,请参考以下文章

从 URLRequestConvertible 扩展时设置多部分请求的最佳方法是啥

字典键的交集是啥

复合主键的一部分可以用作另一个表的复合主键的一部分吗?

部分字典/记录统一?

获取十进制数的整数部分的最佳方法

一对多映射和附加条件列不是外键的一部分