C# 如何使用HashSet<;T>;作为字典的钥匙?
我希望使用C# 如何使用HashSet<;T>;作为字典的钥匙?,c#,.net,collections,C#,.net,Collections,我希望使用HashSet作为字典的键: Dictionary<HashSet<T>, TValue> myDictionary = new Dictionary<HashSet<T>, TValue>(); Dictionary myDictionary=newdictionary(); 我想从字典中查找值,这样包含相同项的HashSet的两个不同实例将返回相同的值 HashSet的Equals()和GetHashCode()的实现似乎没有做到
HashSet
作为字典的键:
Dictionary<HashSet<T>, TValue> myDictionary = new Dictionary<HashSet<T>, TValue>();
Dictionary myDictionary=newdictionary();
我想从字典中查找值,这样包含相同项的HashSet
的两个不同实例将返回相同的值
HashSet
的Equals()
和GetHashCode()
的实现似乎没有做到这一点(我认为它们只是默认值)。我可以重写Equals()
来使用SetEquals()
,但是GetHashCode()
呢?我觉得这里缺少了什么…您可以向字典构造函数提供一个IEqualityComparer
,并在该比较器中实现所需的实现 您可以使用HashSet提供的集合比较器:
var myDictionary=newdictionary(HashSet.CreateSetComparer());
DigeMail的答案显然是实践中更好的选择,因为它使用内置代码而不是重新发明轮子。但我将把它作为一个示例实现
您可以使用实现一个使用
SetEquals
的IEqualityComparer
。然后将其传递给字典的构造函数。类似于以下内容的内容(未进行测试):
类HashSetEqualityComparer:IEqualityComparer
{
public int GetHashCode(HashSet-HashSet)
{
if(hashSet==null)
返回0;
int h=0x14345843;//某个任意数
foreach(哈希集中的元素)
{
h=未选中(h+hashSet.Comparer.GetHashCode(elem));
}
返回h;
}
public bool Equals(HashSet set1,HashSet set2)
{
if(set1==set2)
返回true;
if(set1==null | | set2==null)
返回false;
返回set1.SetEquals(set2);
}
}
注意这里的散列函数是可交换的,这很重要,因为集合中元素的枚举顺序是未定义的
另一个有趣的点是,您不能只使用
elem.GetHashCode
,因为当向集合提供自定义相等比较器时,这将给出错误的结果。不知道存在一个!看起来很有趣(现在我觉得用自定义答案写答案很愚蠢;p)@Marc:eh,我也不知道,直到Jon Skeet给我看了:)当然,我完全忘了字典也使用了比较器-哦!我也不知道:)不幸的是,HashSet.CreateSetComparer()
似乎不存在于.NET核心上(尚未)警告HashSet.CreateSetComparer
将使用EqualityComparer.Default
!!我需要一个对区域性敏感的版本,但不幸的是,HashSetEqualityComparer
有这样一个构造函数,它是内部的。请注意,^
在哈希中通常是个坏主意,但在这种情况下,因为我们知道值是唯一的,所以它可能会起作用。我选择^是因为它可以通勤,因为值是唯一的,因此x^x=0的问题没有那么重要。但可能加法仍然是一个更好的主意。我不知道在评论中提问是否合适,但是你能解释一下或者发布一个链接,详细说明为什么xor在散列中是一个坏主意吗?我认为这是一个好主意,只要参与散列的值也是相等比较的一部分。谢谢xor不好的一个原因是因为重复项会被抵消。对于所有x,x^x=0。例如,你有一个2d向量,使用hashfunctionX^Y
每个X==Y的向量都会发生碰撞。xor是可交换的,这意味着交换属性的值也会产生冲突。e、 g.X=1,Y=5
与X=5,Y=1
冲突只能在少数情况下保证唯一哈希。但是,是的,+和^通常都是组合哈希的错误选择。但是我在这个例子中选择了它们,因为它们是可交换的。组合哈希的常见选择(如hash=hash*primeConstant+elemHash
)在设计上是非交换的。这里需要交换合并。顺便说一句,MS实现使用了^
请记住,如果在将哈希集用作键后对其进行修改,则字典可能会按预期停止工作只要对象用作字典中的键,它就不能以任何影响其哈希值的方式进行更改。根据字典的相等比较器,字典中的每个键都必须是唯一的。
是的,现在使用ImmutableHashSet
将是更好的选择!
var myDictionary = new Dictionary<HashSet<T>, TValue>(HashSet<T>.CreateSetComparer());
class HashSetEqualityComparer<T>: IEqualityComparer<HashSet<T>>
{
public int GetHashCode(HashSet<T> hashSet)
{
if(hashSet == null)
return 0;
int h = 0x14345843; //some arbitrary number
foreach(T elem in hashSet)
{
h = unchecked(h + hashSet.Comparer.GetHashCode(elem));
}
return h;
}
public bool Equals(HashSet<T> set1, HashSet<T> set2)
{
if(set1 == set2)
return true;
if(set1 == null || set2 == null)
return false;
return set1.SetEquals(set2);
}
}