Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/.net/23.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 如何使用HashSet<;T>;作为字典的钥匙?_C#_.net_Collections - Fatal编程技术网

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向量,使用hashfunction
X^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);
    }
}