我有一个带有String的对象,该String包含唯一的id。 (例如“ocx7gf”或“67hfs8”) 我需要提供一个int hascode()的实现,这显然是独一无二的。
如何以最简单/最快的方式将字符串转换为唯一的int?
10倍。
编辑 - 好的。我已经知道String.hashcode是可能的。但不建议在任何地方使用。实际上'如果不推荐任何其他方法 - 我是否应该使用它,如果我的对象在集合中,我需要哈希码。我应该将其连接到另一个字符串以使其更成功吗?
答案 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取回