我正在尝试实现一个IEqualityComparer<string>
,它基本上比较两个字符串,(假设我们有两个字符串x
和y
)x
从y
或y
开始,x
它们应被视为相等。
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
显然,我可以通过从Equals
为所有值返回相同的值来强制调用GetHashCode
方法,但我想知道是否有另一种方法来实现它,因为性能很关键。有没有办法正确地为我的情况实施GetHashCode
方法?
注意:我知道它很模糊,但如果您有更好的想法可以自由编辑,我找不到更好的标题。
编辑:我将在网址上使用此逻辑。在我的情况下,前20个字符是相等的。例如:
http://www.foo.com/bar?id=3
http://www.foo.com/bar?id=3&fooId=23
答案 0 :(得分:4)
问题在于你对平等的定义:平等必须是可传递的。但它不是你的情况。采用以下三个值:
* f
* freeze
* foo
然后f == freeze
和foo == f
,但freeze != foo
。
另请参阅Implementing the Equals Method上的MSDN,其中包含:
当且仅当(x.Equals(y) && y.Equals(z))
返回true时,
x.Equals(z)
才返回true。
正确的相等定义会产生被认为相等的不同值集。如果你有这些,你可以为每个集定义一个“规范”表示,并计算规范值的哈希值,这样每个集合都有其哈希码。但这仅适用于具有传递性的操作(以及可交换和反身,这两个属性都包含在您的定义中)。
由于您的相等定义不可传递,因此您无法定义此类集,因此您也无法找到正确的哈希码。
但它也提出了其他问题。举个例子:
string[] values = { "hell", "hello", "foo", "fooooo" };
var result = values.Distinct(new StringComparer());
您希望将哪些值放入result
?你总是想要最短的版本吗?您的代码无法保证这一点,结果将取决于Distinct
的内部实现。
实施EqualityComparer
可能是您实际问题的次优方法。你想要实现什么目标?
答案 1 :(得分:2)
由于字符串彼此相等,具体取决于您与之比较的字符串,因此任何字符串都可以等于另一个字符串。因此,只有一种方法可以实现GetHashCode
方法;为所有字符串返回相同的值:
public int GetHashCode(string obj) {
return 0;
}
这自然会给人一种可怕的分配。字典将具有O(n)查找时间而不是O(1),但它起作用,并且它是使其适用于这种相等比较的唯一方法。