这取决于我希望看到它使用的值。
如果它通常具有不同的日期值,而不是同一天的不同时间,并且它们在现在的一个世纪之内,我会使用:
unchecked
{
int hash = startDate.Year + endDate.Year - 4007;
hash *= 367 + startDate.DayOfYear;
return hash * 367 + endDate.DayOfYear;
}
这可以很好地分配具有预期值的位,同时减少移位中丢失的位数。请注意,虽然在某些情况下,对质数的依赖在冲突时可能会出奇地糟糕(尤其是当哈希被馈送到使用相同质数的模的东西中以试图避免在产生更小的哈希以在其桶之间分配时发生冲突时) 我选择了高于更明显选择的素数,因为它们只是在上面,所以对于比特分布来说仍然非常“紧”。我不太担心两次使用相同的素数,因为它们以这种方式非常“紧密”,但如果你有一个包含 367 个桶的基于散列的集合,它确实会受到伤害。这很好地(但不是很好)处理过去或未来的日期,但如果假设同一天(时间不同)内将有很少或没有范围的假设是错误的,因为该信息完全丢失,那么这是可怕的。
如果我期待(或为其他方的一般用途而写作,并且无法假设),我会选择:
int startHash = startDate.GetHashCode();
return (((startHash >> 24) & 0x000000FF) | ((startHash >> 8) & 0x0000FF00) | ((startHash << 8) & 0x00FF0000) | (unchecked((int)((startHash << 24) & 0xFF000000)))) ^ endDate.GetHashCode();
第一种方法的工作原理是假设 DateTime 中的通用 GetHashCode 不如我们想要的那么好,这个方法取决于它是否良好,但会混合一个值的位。
它可以很好地处理更明显的棘手情况,例如两个值相同或彼此相距相同的距离(例如很多 1 天或 1 小时的范围)。在第一个示例效果最好的情况下,它并没有那么好,但是如果有很多范围使用同一天但不同的时间,那么第一个示例就完全糟糕了。
编辑:更详细地回应 Dour 的担忧:
Dour 正确地指出,此页面上的某些答案会丢失数据。事实上,它们都丢失了数据。
问题中定义的类有 8.96077483×1037 个不同的有效状态(如果我们不关心每个日期的 DateTimeKind,则为 9.95641648×1036) , GetHashCode 的输出有 4294967296 种可能的状态(其中之一 - 零 - 也将用作空值的哈希码,通常可以与实际代码进行比较)。无论我们做什么,我们都会以 2.31815886 × 1027 的比例减少信息。我们丢失了很多信息!
我们可能会在某些方面比在其他方面失去更多,这可能是真的。当然,通过编写一个有效但非常糟糕的答案,很容易证明某些解决方案可能比其他解决方案损失更多。
(更糟糕的有效解决方案是return 0;,它是有效的,因为它在相等的对象上永远不会出错或不匹配,但尽可能差,因为它会碰撞所有值。基于散列的集合的性能变为 O(n ),并且随着 O(n) 的进行而变慢,因为所涉及的常数比搜索无序列表这样的 O(n) 操作要高。
很难衡量损失了多少。考虑到 XOR 将剩余的信息量减半,在 XORing 之前移位某些位比交换位损失多少。即使是天真的x ^ y 也不会比交换和异或损失更多,它只是在共同值上发生了更多的冲突; swap-and-xor 会在plain-xor 没有的值上发生冲突。
一旦我们在不丢失更多信息但返回 4294967296 或接近 4294967296 个可能值且这些值之间分布良好的解决方案之间做出选择,那么问题就不再是多少信息丢失了(答案只剩下4.31376821×10-28个原始信息)但是哪些信息丢失了。
这就是我上面的第一个建议忽略时间组件的原因。一天中有 864000000000 个“滴答声”(DateTime 的分辨率为 100 纳秒单位),我故意丢弃其中的两块滴答声(两者之间的可能值是 7.46496×1023),因为我正在考虑一个无论如何都不使用该信息的场景。在这种情况下,我特意构建了机制,以选择 哪些 信息丢失,从而改善给定情况下的哈希值,但如果我们有不同的值,它绝对毫无价值开始和结束日期不在同一天,而是在不同的时间。
同样,x ^ y 不会比其他任何一个丢失更多的信息,但它确实丢失的信息比其他选择更可能是重要的。
如果没有任何方法可以预测哪些信息可能很重要(尤其是如果您的课程是公开的并且其哈希码被外部代码使用),那么我们可以安全地做出的假设会受到更多限制.
总的来说,prime-mult 或 prime-mod 方法在丢失信息方面比基于移位的方法更好,但具有讽刺意味的是,当在基于哈希的方法中可能发生的进一步哈希中使用相同的素数时考虑到相同的目标(没有数字与自身相对质数!甚至质数)在这种情况下,它们会更糟。另一方面,如果将基于移位的方法输入到基于移位的进一步哈希中,则基于移位的方法确实会失败。任意数据和任意使用都没有完美的散列(除非一个类的有效值很少并且我们将它们全部匹配,在这种情况下,它是一种比我们生成的散列更严格的编码)。
简而言之,无论做什么,您都会丢失信息,重要的是您丢失了哪个。