【问题标题】:64bit HashCodes, IEqualityComparer & Intersect/Except64 位哈希码、IEqualityComparer & Intersect/Except
【发布时间】:2014-11-11 21:05:10
【问题描述】:

我正在从字符串生成 64 位哈希码,并将此值存储在数据库中

是否可以用 64 位长类型而不是 32 字节 int 覆盖 GetHashCode?​​p>

如果这不可能,是否可以在其他地方实现 Equals 和 GetHashCode,并且仍然使用 except 和 Intersect?

public class RecordComparer : IEqualityComparer<Record>
{
    public bool Equals(Record x, Record y)
    {
        if (ReferenceEquals(x, y)) return true;
        if (x == null || y == null) return false;
        return x.RecordHash.Equals(y.RecordHash);
    }

    public long GetHashCode(Record obj)
    {
        return obj.RecordHash;
    }
 }

【问题讨论】:

  • 由于散列冲突,使用散列来表示相等是值得怀疑的。
  • 适用于 32 位哈希整数...在 100,000 条记录后开始发生冲突。然而,64 位哈希保证了非常低的冲突率。
  • “64 位哈希保证了非常低的冲突率”:是的,它们确实如此。但不是平等。这是IEqualityComparer&lt;T&gt;Equals() 的正确实现所需要的。
  • 请解释一下IntersectExcept 你在这里说的是什么,以及它们与你的问题有什么关系。这些操作在 .NET 中的唯一实现无论您的哈希码是 32 位还是 64 位都同样有效,因为它们不使用哈希码来确定实际相等性。
  • 有道理。但是,就我的目的而言,64 int 足够独特,我可以忍受每隔几万亿条记录发生一次碰撞。是否可以覆盖 GetHashCode 以返回 64 位整数?

标签: c# hashcode gethashcode iequalitycomparer


【解决方案1】:

内置集合、算法和接口都不支持 64 位哈希码。你必须自己建造一切。您需要一个完整的并行基础架构。

这很可能不值得付出努力。相反,使用 32 位哈希码并依靠您的相等比较来确保不会发生错误匹配。无论如何,这是正确性所必需的。

也许这个问题是基于一个误解:

基本上我会有 2 个 64 位哈希码整数列表。一世 需要能够在这两个列表上使用除/相交来找到 差异,基于 64 位 hascode 值。一切照旧, IEqualityComparer 仅适用于 32 位整数。

只需将此哈希码视为内置集合和算法中的键。您可以使用 Except 处理这些列表。

【讨论】:

  • 我可能可以围绕这个想法工作,但是我的列表实际上是一个对象,一个属性是哈希值,另一个属性是记录的 ID。如果我只是制作一个 long 和 intersect 的列表,我还必须拉出对象列表以获取与 except/Intersect 结果关联的正确记录 ID
  • web 上有扩展方法,叫做 exceptBy 和 IntersectBy。他们做你显然需要的事情。如果您不能使用它们,请使用连接或字典自己实现此算法。这些似乎都没有涉及哈希码的问题。
【解决方案2】:

假设您不关心具有相同哈希码的不同记录可能引起的问题,因此即使它们不同,您也可以简单地实现RecordComparer

public class RecordComparer : IEqualityComparer<Record>
{
    public bool Equals(Record x, Record y)
    {
        if (ReferenceEquals(x, y)) return true;
        if (x == null || y == null) return false;
        return x.RecordHash.Equals(y.RecordHash);
    }

    public int GetHashCode(Record obj)
    {
        return unchecked((int) obj.RecordHash);
    }
}

IEqualityComparer&lt;T&gt; 是通过返回通过截断标识记录的 64 位哈希码创建的 32 位哈希码来正确实现的。

没有要求GetHashCode 应该为不相等的记录返回唯一的哈希码。但是,避免冲突会使像Dictionary&lt;Record&gt; 这样的通用集合性能更好,并且基于 64 位哈希码的 32 位哈希码可能是最好的做法。

如果您查看Enumerable.ExceptEnumerable.Intersect 的源代码,您会发现它们使用了内部类Set&lt;T&gt;,这是某种哈希表,因此您对GetHashCode 的实现可能会影响您的性能码而不是正确性(只要相等的记录返回相同的哈希码)。

【讨论】:

  • 在我看来,64 位值在被发回之前会被转换为 32 位,这在我将两个 64 位整数列表相交以获得差异的情况下并没有真正的帮助。但是我从来没有用过unchecked,所以我的想法可能不正确
  • @user1691808: unchecked 只是为了避免在打开checked 的情况下编译代码时出现任何异常(默认为关闭)。演员表基本上将 64 位值截断为 32 位,这样做时您不想要 OverflowException
猜你喜欢
  • 1970-01-01
  • 2023-04-09
  • 2011-12-14
  • 1970-01-01
  • 2011-06-28
  • 1970-01-01
  • 1970-01-01
  • 2016-02-06
  • 2013-03-05
相关资源
最近更新 更多