我正在使用Scala代码,该代码将一组唯一字符串转换为唯一ID。我应用了HashCode(),但是我的数字负数,我只需要与正数一起工作。我知道我必须使用数学来摆脱负值,但我不确定这是否是正确的解决方案。如果我之前阅读,类似的事情可以解决我的问题
math.abs(hashCode()) * constant % size
如何确定正确的常数?大小是否意味着字符串的总数?
与该主题有关的先前问题通过使用数学解决了问题。仅如果字符串总数很大,可能会发生溢出,并且也有机会获得负数。通过将结果乘以恒定并采用大小的模型可能会有所帮助。这就是为什么我需要了解如何确定常数和大小?
还有另一种方法可以获取唯一字符串的唯一数字?
我们可以以另一种方式来表达您的问题:如何从具有相同范围的签名号码获得无符号号码?
假设您正在使用整数。它的值从-2147483648到2147483647。现在您需要将此值转换为正范围0到2147483647。
步骤1:
添加一个常数将范围向上移至0。您可以通过将2147483648添加到值中来做到这一点。但是现在最高的值大大远大于最大值
步骤2:
因此,使用Modulo将值移回了所需的范围。
例如,考虑值-2000和2000000000。
| STEP | MIN VALUE | EXAMPLE 1 | EXAMPLE 2 | MAX VALUE |
|-------------------|------------|------------|------------|------------|
| original |-2147483648 | -2000 | 2000000000 | 2147483647 |
| add 2147483648 | 0 | 2147481648 | 4147483648 | 4294967295 |
| modulo 2147483648 | 0 | 2147481648 | 2000000001 | 2147483647 |
所以最终公式是:
(NUMBER + 2147483648) % 2147481648
警告:
哈希代码并非旨在提供独特的值。有两个不同的字符串有可能获得相同的哈希。同样,在哈希(例如Division,Modulo)上进行的任何缩放操作都可以进一步降低唯一性。
从 Int
剥离符号,您只需使用 .abs
即可。它确实在Int.MinValue
上破裂,但是您可以特殊情况:
def stripSign(n: Int) = math.abs(n) max 0
或简单地丢下标志:
def stripSign2(n: Int) = n & Int.MaxValue
或只是使用负数(无论如何它们怎么了?)。
到您的另一个问题,您不能将一堆独特的字符串转换为INT,并保证不会有重复的(出于简单的原因, Int
s都要多。因此,如果您想为它们分配一个唯一的INT,则在弦乐器用完之前,您会用完INT),因此您必须能够处理碰撞,无论多么频繁。
您只能通过使哈希散布更长的时间来降低碰撞的概率(使用32位哈希代码,在大约75000个字符串中,您的概率约为至少50%,有31位碰撞,有31位。(如果您不想要负数),则为55000,但是使用64位哈希,"魔术数字"约为5亿亿,前提是您的哈希功能足够好,并且产生分布非常均匀的数字)。