【问题标题】:I'm implementing a CaseAccentInsensitiveEqualityComparer for Strings. I'm not sure how to implement the GetHashCode我正在为字符串实现 CaseAccentInsensitiveEqualityComparer。我不确定如何实现 GetHashCode
【发布时间】:2012-10-22 18:41:26
【问题描述】:

我的代码是这样的:

public class CaseAccentInsensitiveEqualityComparer : IEqualityComparer<string>
    {
        public bool Equals(string x, string y)
        {
            return string.Compare(x, y, CultureInfo.InvariantCulture, CompareOptions.IgnoreNonSpace | CompareOptions.IgnoreCase) == 0;
        }

        public int GetHashCode(string obj)
        {
             // not sure what to put here
        }
    }

我知道GetHashCode 在这种情况下的作用,我缺少的是如何生成objInvariantCultureIgnoreNonSpaceIgnoreCase 版本,以便我可以返回它的HashCode .

我可以自己从obj 中删除变音符号和大小写,然后返回hashcode,但我想知道是否有更好的选择。

【问题讨论】:

  • 你打算将它与字典、HashSet 或其他任何使用哈希表的东西一起使用吗?
  • 这个类的目的是什么?您能否提供一个可以避免的语法示例?

标签: c# .net string string-comparison


【解决方案1】:

GetHashCode() 中返回 0 有效(正如 @Michael Perrenoud 所指出的那样),因为 DictionariesHashMaps 调用 Equals(),前提是两个对象的 GetHashCode() 返回相同的值。
rule 是,如果对象相等,GetHashCode() 必须返回相同的值。
缺点是HashSet(或Dictionary)的性能下降到与使用列表相同的程度。要查找项目,每次比较都必须调用 Equals()
一种更快的方法是转换为不区分重音的字符串并获取其哈希码。

删除此 post 的重音(变音符号)的代码

static string RemoveDiacritics(string text)
{
    return string.Concat(
        text.Normalize(NormalizationForm.FormD)
        .Where(ch => CharUnicodeInfo.GetUnicodeCategory(ch) !=
                                        UnicodeCategory.NonSpacingMark)
    ).Normalize(NormalizationForm.FormC);
}

比较代码:

public class CaseAccentInsensitiveEqualityComparer : IEqualityComparer<string>
{
    public bool Equals(string x, string y)
    {
        return string.Compare(x, y, CultureInfo.InvariantCulture, CompareOptions.IgnoreNonSpace | CompareOptions.IgnoreCase) == 0;
    }

    public int GetHashCode(string obj)
    {
        return obj != null ? RemoveDiacritics(obj).ToUpperInvariant().GetHashCode() : 0;
    }

    private string RemoveDiacritics(string text)
    {
        return string.Concat(
            text.Normalize(NormalizationForm.FormD)
            .Where(ch => CharUnicodeInfo.GetUnicodeCategory(ch) !=
                                          UnicodeCategory.NonSpacingMark)
          ).Normalize(NormalizationForm.FormC);
    }
}

【讨论】:

    【解决方案2】:

    啊,对不起,我的方法搞混了。当我在刚刚返回对象本身的哈希码 return obj.GetHashCode(); 之前实现了类似的东西时,它总是会进入 Equals 方法。


    好的,经过一番困惑,我相信我已经明白了。我发现返回零总是会强制比较器使用Equals 方法。我正在寻找我实现它的代码来证明这一点并将其放在这里。


    这是证明它的代码。

    class MyArrayComparer : EqualityComparer<object[]>
    {
        public override bool Equals(object[] x, object[] y)
        {
            if (x.Length != y.Length) { return false; }
            for (int i = 0; i < x.Length; i++)
            {
                if (!x[i].Equals(y[i]))
                {
                    return false;
                }
            }
            return true;
        }
    
        public override int GetHashCode(object[] obj)
        {
            return 0;
        }
    }
    

    【讨论】:

    • 我认为你搞错了。也许您应该使用 cmets。我没有对你投反对票,但我怀疑阅读问题和你的答案并认为它没有帮助的人。
    • @Wug,您是否阅读了我的编辑或我的答案的缓存版本?获得您对我的编辑的傲慢反馈会很有帮助。
    • 我不是反对者,但我认为,当您将 IEqualityComparer 传递给 Dictionary 或 HashMap 时,字典将使用 IEqualityComparer 来确定其项目的哈希值(因为它不能使用通常的 GetHashCode,因为对象没有被正常比较)。返回一个零数字会混淆这些字典。
    • @AndréPena,我让自己感到困惑。总是返回零,这将强制它使用Equals 方法。
    • @BigM:如果您在发布后的 5 分钟内对其进行了编辑,则该编辑将与原始帖子混为一谈,并且不会显示编辑历史记录。我只是像我看到的那样称呼它,无需全力防御。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-10-05
    • 1970-01-01
    • 2011-04-23
    • 2017-02-08
    相关资源
    最近更新 更多