如何针对这种情况实现GetHashCode

本文关键字:情况 实现 GetHashCode 何针 | 更新日期: 2023-09-27 18:19:30

我正在尝试实现一个IEqualityComparer<string>,它基本上比较两个字符串,(假设我们有两个字符串xy)如果xy开头,或者yx开头,它们应该被视为相等。

public bool Equals(string x, string y)
{
    return x.StartsWith(y) || y.StartsWith(x);
}
public int GetHashCode(string obj)
{
    return obj.GetHashCode();
}

当然,实现Equals方法很容易。但GetHashCode不是,我想不出任何方法来正确实现它。我写了一个这样的测试程序:

string[] values = {"hell", "hello", "foo", "fooooo"};
var result = values.Distinct(new StringComparer());
foreach(var x in result)
   Console.WriteLine(x);

由于GetHashCode:,我得到了错误的结果

hell
hello
foo
fooooo

显然,我可以通过从GetHashCode为所有值返回相同的值来强制调用Equals方法,但我想知道是否有其他方法可以实现它,因为性能至关重要。有没有一种方法可以针对我的情况正确地实现GetHashCode方法?

注意:我知道它很模糊,但我找不到更好的标题,如果你有更好的想法,你可以自由编辑。


编辑:我将在web URL中使用此逻辑。在我的情况下,前20个字符是相等的。例如:

http://www.foo.com/bar?id=3
http://www.foo.com/bar?id=3&fooId=23

如何针对这种情况实现GetHashCode

问题在于平等的定义:平等必须是可传递的。但你的情况并非如此。取以下三个值:

* f
* freeze
* foo

然后是f == freezefoo == f,而不是freeze != foo

另请参阅MSDN关于实现Equals方法的内容,其中写道:

当且仅当x.Equals(z)返回真时,(x.Equals(y) && y.Equals(z))返回真。

平等的正确定义产生了被认为是平等的不同的价值观。如果你有这些,你可以为每个集合定义一个"规范"表示,并计算规范值的哈希,这样每个集合都有自己的哈希代码。但这只适用于传递性的运算(以及交换性和自反性,这两个性质都在你的定义中)。

由于你对等式的定义是不可传递的,你不能定义这样的集合,所以你也找不到合适的哈希码。

但这也引发了其他问题。举个例子:

string[] values = { "hell", "hello", "foo", "fooooo" };
var result = values.Distinct(new StringComparer());

您希望result中包含哪些值?你总是想要最短的版本吗?您的代码不会保证这一点,结果将取决于Distinct的内部实现。

实现EqualityComparer可能是解决实际问题的次优方法。你想达到什么目的?

由于字符串彼此相等,这取决于您将它们与哪个字符串进行比较,因此任何字符串都可以与另一个字符串相等。因此,只有一种方法可以实现CCD_ 22方法;为所有字符串返回相同的值:

public int GetHashCode(string obj) {
  return 0;
}

这自然会造成可怕的分配。字典的查找时间是O(n),而不是O(1),但它是有效的,而且这是使它适用于这种相等比较的唯一方法。