【发布时间】:2018-12-13 12:04:05
【问题描述】:
当需要在字符串之间进行近似比较时,基本的Levenshtein Distance 可以提供帮助。它测量与另一个字符串相等所需的字符串修改量:
"aaaa" vs "aaab" => 1
"abba" vs "aabb" => 2
"aaaa" vs "a" => 3
当使用Dictionary<T, U> 时,可以提供自定义IEqualityComparer<T>。可以将 Levenshtein 距离实现为 IEqualityComparer<string>:
public class LevenshteinStringComparer : IEqualityComparer<string>
{
private readonly int _maximumDistance;
public LevenshteinStringComparer(int maximumDistance)
=> _maximumDistance = maximumDistance;
public bool Equals(string x, string y)
=> ComputeLevenshteinDistance(x, y) <= _maximumDistance;
public int GetHashCode(string obj)
=> 0;
private static int ComputeLevenshteinDistance(string s, string t)
{
// Omitted for simplicity
// Example can be found here: https://www.dotnetperls.com/levenshtein
}
}
所以我们可以使用模糊字典:
var dict = new Dictionary<string, int>(new LevenshteinStringComparer(2));
dict["aaa"] = 1;
dict["aab"] = 2; // Modify existing value under "aaa" key
// Only one key was created:
dict.Keys => { "aaa" }
完成所有这些设置后,您可能已经注意到我们没有在LevenshteinStringComparer 中实现正确的GetHashCode,字典将不胜感激。作为关于哈希码的一些经验法则,我会使用:
- 不相等的对象不应具有相同的哈希码
- 相等的对象必须具有相同的哈希码
我能想象的唯一可能遵循这些规则的哈希函数是一个常数,就像在给定代码中实现的那样。虽然这不是最佳的,但是当我们开始例如获取字符串的默认哈希时,aaa 和 aab 最终会得到不同的哈希,即使它们被处理为相等。进一步思考这意味着所有可能的字符串都必须具有相同的哈希值。
我说的对吗? 为什么当我使用带有哈希冲突的默认字符串哈希函数作为比较器时,字典的性能会变得更好? 这不应该使字典中的哈希桶无效吗?
public int GetHashCode(string obj)
=> obj.GetHashCode();
【问题讨论】:
-
我在这里看到了一个问题。如果您允许距离 1 并且已经有一个带有 'aab' 的项目,添加 'aaa' 或 'abb' 的结果相同,但如果第一个项目是 'abb',则最终结果不同。
-
这让我想起了Ring Species - 作为生活在邻近地区的动物物种仍然可以交配的想法,当你绕过一个大障碍物,如山脉或海洋时,你可以最终使环两端的最后两只动物无法交配。什么时候两种动物不再是同一个物种而变成不同的物种?你的钥匙也一样。我可以从您认为不同的两个键开始,但我可以找到一系列中间键,这些中间键将被视为将前两个键连接在一起的匹配项。
-
这不是重复的,但我认为这个讨论涉及...stackoverflow.com/questions/15377043/…
-
@PepitoSh 是的,这本词典在某些方面很奇怪,但你提到的是否违反了我们应该遵循的一些具体实施规则?
-
一点也不。我的世界更具确定性,我看不出这种字典的用途。也许如果你带来了一些潜在的用例。
标签: c# dictionary hash hashtable fuzzy-search