【问题标题】:GroupBy on strings (hashcode collision)字符串上的 GroupBy(哈希码冲突)
【发布时间】:2013-07-26 09:19:56
【问题描述】:

我有一个字符串数组(大约 2000 个),我想使用 IEnumerable.GroupBy 对相等的字符串进行分组。

问题是虽然有很多散列冲突,例如“mysteriously”“well”。这可能是因为 GroupBy 使用了 GetHashCode(),它返回的 int 太小(或者 String 类的 GetHashCode 函数没有很好地实现)。

我想你可以尝试实现一个重写的 GetHashCode 函数或定义一个自定义 IEqualityComparer 并使用不同的哈希码,但没有任何方法可以直接比较它们或不同?我知道这需要更长的时间,但少量是可以接受的。我该如何解决这个问题?

【问题讨论】:

  • GetHashCode Equals一起工作。它只是为了帮助实现一个基于哈希的 Map 并且可以显示 non-equality 但它不能证明相等。标准的 String.GetHashCode 应该可以很好地实现这个目的(请提供一个链接来支持“尚未很好地实现”):一个整数可以表示超过 2000 个值,偶尔的冲突无关紧要。你不能继承 String,但你可以使用 IEqualityComparer .. 虽然我不知道为什么。
  • 另外,关于 "mysteriously".GetHashCode() == "well".GetHashCode() 的断言在 .NET 4.5 中是错误的——我不知道其他版本,但我会感到非常惊讶如果任何 .NET 生成的字符串哈希代码如提示的那样“绝对糟糕”。 (但是,请记住,哈希算法可以成为冲突攻击的目标:这与导致相同哈希码的随机输入有很大不同。这些攻击,实际上是一般的“重复哈希”,会影响性能,但不会影响正确性。)
  • 是的,很抱歉,我将每个组中的所有字符串都打印出来了,但我没有想到的是字符串可以包含多行,因此看起来像是匹配,调试不好我猜对了!
  • 很高兴问题解决了:D

标签: c# linq


【解决方案1】:

字符串上的 GroupBy 只会将相等的字符串组合在一起,无论它们是否具有相同的哈希码。由于 GroupBy 在后台使用哈希表,许多具有相同哈希码的不同字符串可能会稍微降低性能,但仍会给出正确的答案。

为了向自己证明这一点,请注意,即使使用具有糟糕散列函数的自定义 IEqualityComparer,GroupBy 也能很好地工作:

void Main()
{
    var groups = new[] { "a", "a", "b", "b", "c", "c" }.GroupBy(s => s, new BadComparer())
        .Select(g => string.Join(",", g))
        .ToArray();
    Console.WriteLine(string.Join(Environment.NewLine, groups));
    // this prints:
    // a,a
    // b,b
    // c,c      
}

public class BadComparer : IEqualityComparer<string> {
    public bool Equals(string a, string b) { return a == b; }
    public int GetHashCode(string s) { return 0; }
}

还要注意,按字符串本身而不是按其哈希码进行分组很重要:

myStrings.GroupBy(s =&gt; s) // works

myStrings.GroupBy(s =&gt; s.GetHashCode()) // doesn't work

【讨论】:

  • 嗯,这很奇怪,我在这里有一个证据,GroupBy 给了我一个无效的组,但如果我测试单个数组中的单词它们将不匹配,请稍等
猜你喜欢
  • 1970-01-01
  • 2019-04-04
  • 1970-01-01
  • 2010-09-20
  • 2018-08-04
  • 2014-11-30
  • 2010-10-18
  • 2018-07-02
相关资源
最近更新 更多