2016-11-17 62 views
0

我有一个这样的词典:如何通过密钥哈希码访问字典?

Dictionary<MyCompositeKey, int> 

显然MyCompositeKey是I类设计它实现IEqualityComparer并因此具有GetHashCode方法。

据我所知,词典使用密钥的哈希来访问值,所以这里是我的问题:

虽然我可以通过dict.TryGetValue(new MyCompositeKey(params))轻松访问的价值,我想摆脱掉new头顶上的每个访问。

由于这个原因,我想知道是否有一种方法直接从密钥的哈希值(我可以用非常低的开销计算)访问值。

+3

'TKey'(在你的情况下'MyCompositeKey')不应该实现'IEqualityComparer';那是错的。 'MyCompositeKey'应该覆盖'Equals(object)'和'GetHashCode()',否则你应该传递___另一个实现'IEqualityComparer <>'的对象到'Dictionary <,>'构造函数。 –

+0

我可以删除实现并保留'Equals'和'GetHashCode'覆盖。这不会改变我的问题。 – Fylax

+0

对,这只是一个评论,不是对问题的回答。但不要混淆所有类和结构体继承(来自'object')的'GetHashCode()'方法与'IEqualityComparer '中存在的'GetHashCode(T)'方法。 –

回答

2

没有办法来做到这一点。

请注意,可能会发生散列冲突,因此Dictionary<,>中可能有许多键匹配给定散列。我们需要Equals找出哪个(如果有的话)是正确的。

你说说new开销。你确定它对你的情况有意义吗?

如果是,你可以考虑做一个MyCompositeKey不变struct代替class。在某些情况下,它可能会更快,无需垃圾收集器从内存中删除所有这些“松散”的密钥。

如果MyCompositeKeystruct,表达仅new MyCompositeKey(params)加载所有params到调用堆栈(或CPU寄存器或任何运行时的数字是最好的)。


增加:如果你去一个struct,考虑实施IEquatable<>。它看起来像这样:

struct MyCompositeKey : IEquatable<MyCompositeKey> 
{ 
    // readonly fields/properties 

    public override bool Equals(object obj) 
    { 
    if (obj is MyCompositeKey) 
     return Equals((MyCompositeKey)obj); // unbox and go to below overload 

    return false; 
    } 

    public bool Equals(MyCompositeKey other) // implements interface, can avoid boxing 
    { 
    // equality logic here 
    } 

    public override int GetHashCode() 
    { 
    // hash logic here 
    } 
} 
+0

我发现结构分配在某种程度上更快(虽然需要更多的RAM)。由于我有时间成本,但没有RAM成本(我在目标计算机中有16GB),我猜想使用结构可能是获胜的想法。 – Fylax

+0

@Fylax假设你实际使用它们的目的,结构总是比类更快。 – Krythic

+0

@Krythic它基本上是一个'KeyValuePair'(它是一个结构体),具有自定义'Equals'和'GetHashCode',所以它应该是有意义的 – Fylax

1

你不能那样做。

A Dictionary<TKey, TValue>使用内部存储桶集合,您不能从课堂外访问 - 它是private

正如可以在source code看到,该接入方法首先确定铲斗(根据哈希码),然后通过索引来访问项目:

public bool TryGetValue(TKey key, out TValue value) 
{ 
    int i = FindEntry(key); 
    if (i >= 0) 
    { 
     value = entries[i].value; 
     return true; 
    } 

    value = default(TValue); 
    return false; 
} 

private int FindEntry(TKey key) 
{ 
    if (buckets != null) 
    { 
     int hashCode = comparer.GetHashCode(key) & 0x7FFFFFFF; 
     for (int i = buckets[hashCode % buckets.Length]; i >= 0; i = entries[i].next) 
     { 
      if (entries[i].hashCode == hashCode && comparer.Equals(entries[i].key, key)) 
       return i; 
     } 
    } 

    return -1; 
}