如何从唯一的字符串生成唯一的int?

时间:2011-03-28 13:10:07

标签: java casting unique

我有一个带有String的对象,该String包含唯一的id。 (例如“ocx7gf”或“67hfs8”) 我需要提供一个int hascode()的实现,这显然是独一无二的。

如何以最简单/最快的方式将字符串转换为唯一的int?

10倍。

编辑 - 好的。我已经知道String.hashcode是可能的。但不建议在任何地方使用。实际上'如果不推荐任何其他方法 - 我是否应该使用它,如果我的对象在集合中,我需要哈希码。我应该将其连接到另一个字符串以使其更成功吗?

6 个答案:

答案 0 :(得分:20)

不,你需要有一个返回唯一值的实现,“显然”,因为显然大多数实现都会被破坏。

你想要做的是,在比特上有一个很好的分布,特别是对于普通值(如果任何值比其他值更常见)。除非您对格式有特殊了解,否则只使用字符串本身的哈希码就是最好的。

通过对id格式限制的特殊了解,可以自定义并获得更好的性能,但错误的假设更可能使事情变得更糟。

编辑:比特的良好传播。

如此处和其他答案中所述,完全唯一是不可能的,并且哈希冲突是可能的。哈希使用方法知道这个并且可以处理它,但 会影响性能,因此我们希望碰撞很少见。

此外,散列通常会被重新散列,因此我们的32位数字最终可能会减少到例如一个在0到22的范围内,我们希望在尽可能好的分布范围内。

我们还希望平衡这一点,而不是花费很长时间来计算我们的哈希,它本身就成了一个瓶颈。不完美的平衡行为。

一个糟糕的哈希方法的典型例子是一对X,Y整数的坐标:

return X ^ Y;

虽然这可以很好地从4 ^ 32个可能的输入中返回2 ^ 32个可能的值,但在实际使用中,使用X和Y相等的坐标集是很常见的({0,0} ,{1,1},{2,2}等等,它们全部散列为零,或匹配对({2,3}和{3,2})将散列到相同的数字。我们可能会更好地服务于:

return ((X << 16) | (x >> 16)) ^ Y;

现在, 就像许多可能的值一样,这比前者更糟糕,但它往往在现实世界中更好地服务。

当然,如果您正在编写一个通用课程(不知道有哪些可能的输入)或者更好地了解手头的目的,那么就会有不同的工作。例如,如果我使用Date对象但知道它们都只是日期(时间部分总是午夜)并且只在几年之内,那么我可能更喜欢仅使用日,月和年份的低位数,超过标准的数字。 Date的作者虽然不能运用这些知识,但必须尽力满足每个人的需要。

因此,如果我知道一个给定的字符串总是由[az]或[0-9]范围内的6个不区分大小写的字符组成(你似乎是这样,但是从你的问题,那么我可能会使用一个算法,为每个字符分配一个0到35之间的值(每个字符36个可能的值),然后遍历字符串,每次将当前值乘以36并添加下一个字符的值。

假设在ID中有一个很好的传播,这将是要走的路,特别是如果我订单使得我的哈希中的较低有效数字与id中最频繁更改的字符匹配(如果这样的调用可以因此可以很好地重新散列到较小范围内。

然而,由于缺乏对格式的这种了解,我无法确定地进行调用,而且我可能会使事情变得更糟(对于散列质量很少或甚至负增益的算法较慢)。

您拥有的一个优点是,由于它本身就是一个ID,因此可能没有其他不相等的对象具有相同的ID,因此不需要检查其他属性。这并不总是成立。

答案 1 :(得分:11)

您无法从无限长度的字符串中获取唯一的整数。有4亿个(2 ^ 32)个唯一的整数,但几乎是无限数量的独特字符串。

String.hashCode()不会给你唯一的整数,但它会尽力根据输入字符串给你不同的结果。

修改

您编辑的问题表明不建议使用String.hashCode()。这是不正确的,建议,除非您有一些特殊原因不使用它。如果您有特殊原因,请提供详细信息。

答案 2 :(得分:5)

看起来你有一个36号基数(a-z + 0-9)。为什么不使用Integer.parseInt(s, 36)将其转换为int?显然,如果有太多唯一ID,它将不适合int,但在这种情况下,你会因为使用String.hashCode()而无法使用{{1}}。尽力接近独特。

答案 3 :(得分:3)

除非你的字符串在某种程度上受到限制,否则你的整数比你想要转换的字符串容纳更多的位,你不能保证唯一性。

假设您的字符串有32位整数和64个字符的字符集。这意味着每个字符有六位。这将允许您将五个字符存储为整数。不仅如此,它还不适合。

答案 4 :(得分:0)

一种方法是为每个字母分配一个值,并且字符串的每个位置都是多个,即a = 1,b = 2,依此类推,那么第一个数字中的所有内容(从左到右读取)都会乘以素数,下一个素数等等,这样最后的数字乘以大于该数字中可能的子集数量的素数(26 + 1表示空格或52 + 1表示数据)等等其他支持的字符)。如果数字被映射回第一个数字(最左边的字符),您将从唯一字符串生成的任何数字映射回1或6,无论第一个字母是什么,都会给出一个唯一值。

狗可能是30,3(15),101(7)或782,而上帝33,3(15),101(4)或482。比生成的唯一字符串更重要的是它们可以用于生成保留原始数字,如30(782)对于某些12(782)是唯一的,以区分相似的字符串,如果你曾设法克服独特的可能性。狗永远是狗,但它永远不会是猫或老鼠。

答案 5 :(得分:0)

用五位二进制数字表示每个字符串字符,例如。 a乘00001 b乘00010等,因此32种组合是可能的,例如,cat可能写为00100 00001 01100,然后将该二进制转换为十进制,例如。这将是4140,因此cat将是4140,类似地,您可以通过先将cat转换为二进制并将五位数的二进制映射到字符串来将cat从4140取回