【问题标题】:how can i generate a unique int from a unique string?如何从唯一的字符串生成唯一的 int?
【发布时间】:2011-03-28 13:10:07
【问题描述】:

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

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

10 倍。

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

【问题讨论】:

  • 你不能。只有这么多的 int 值,但有无限多的字符串。因此,不是每个字符串都可以有自己的 int hascode。不过,您可以计算一个唯一的 BigInteger 哈希码。
  • @Ingo,我看不到 BigIntegers 可用作哈希码的许多用途。它们往往太大了。
  • @Jon,确实如此。琴弦本身可能是几乎最紧凑的琴键。我添加 BigInteger 的想法只是为了完整性。
  • 不,到处都推荐使用哈希码,并被多个标准容器隐式使用。如果您有特定的理由不使用它来解决给定的问题,请详细说明,否则人们将不知道为什么不直接使用 Java 字符串哈希码背后的非常好的代码。
  • 规则 #1:如果 JDK 已经提供了东西,就不要自己写东西。 JDK 代码一直在更新,因此您只需更新到较新的 Java 版本即可获得性能更好的实现。如果您自己编写它,它不仅会比 JDK 提供的更糟糕(让我们在这里真实一点:这是您与整个 Sun/Oracle 程序员团队的较量)您承担了负担维护它。不要试图变得聪明,只要做到String.hashCode()。您想要优化您的代码,您的代码中可能还有很多其他地方可以从优化中受益。

标签: java casting unique


【解决方案1】:

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

您想要做的是在位之间进行良好的分布,尤其是对于常见值(如果任何值比其他值更常见)。除非您对格式有特殊了解,否则最好只使用字符串本身的哈希码。

凭借对 id 格式限制的特殊了解,可以进行自定义并获得更好的性能,尽管错误的假设更有可能使事情变得更糟。

编辑:关于比特的良好传播。

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

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

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

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

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 的作者虽然无法在这些知识上工作,但必须尝试满足每个人的需求。

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

假设在 id 中分布良好,这将是可行的方法,特别是如果我的顺序使得我的哈希中的低有效数字与 id 中最频繁变化的字符匹配(如果这样的调用可以被制作),因此可以很好地在更小的范围内重新散列。

但是,由于缺乏对格式的这种了解,我无法确定地做出那个调用,而且我很可能会让事情变得更糟(算法变慢,哈希质量几乎没有甚至是负面的增益)。

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

【讨论】:

  • +1 用于指出 hascode 在定义上并不是唯一的。
  • 您能否详细说明“在位之间有良好的分布”。我无法理解那部分/
  • 嘿,非常感谢。那很有趣。由于我真的不知道我的传播范围会有多广,或者什么是最频繁更改的字符,所以我将使用 String.hashcode() 进行映射的根源。我想我从这些 cmets 中了解到这是非常合理的解决方案。如果我的收藏发生冲突,我的律师会与您联系。我的律师将在此页面上联系到你们所有人。同时感谢开导。
  • 您的律师可能会指出免责声明,并建议如果有很多冲突(少数无关紧要,除非集合本身写得不好),那么是时候更详细地检查哈希了,从重新阅读以上内容开始;)
【解决方案2】:

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

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

编辑

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

【讨论】:

  • 严格来说不是无限的,但仍然有 65536^(2^31) 左右(包括那些使用 Unicode 非字符和无效代理组合的),所以远远超过 20 亿。
  • 改为“几乎无限”:-)
  • 嘿,“无限”是一个强词:)
  • 如果你能想出更好的措辞,请做我的客人 :-) 一旦你一方面达到“40亿”,“真的很大”似乎有点弱...
  • “真的,真的,真的,很大”? ;)
【解决方案3】:

看起来你有一个以 36 为基数的数字 (a-z + 0-9)。为什么不使用 Integer.parseInt(s, 36) 将其转换为 int?显然,如果唯一 ID 太多,它不适合 int,但在这种情况下,你对唯一整数不走运,需要使用 String.hashCode() 来获取,这会尽力接近独特。

【讨论】:

  • 使用long 可能值得考虑,而不是int
  • @Peter hashCode() 返回 int,而不是 long。否则我会建议这样做。
  • 如果这纯粹是为了在 hashCode() 中使用,结果不需要是唯一的。我假设OP知道这一点。 ;)
  • @Peter True。很难确定他是想要一个唯一的整数,还是想要一个哈希码。如果只是一个唯一的整数,long 甚至 BigInteger 都值得考虑。
  • 我怀疑他想要多合一。 ;) +1 顺便说一句。
【解决方案4】:

除非您的字符串在某些方面受到限制,或者您的整数比您尝试转换的字符串包含更多位,否则您无法保证唯一性。

假设您的字符串有一个 32 位整数和一个 64 个字符的字符集。这意味着每个字符六位。这将允许您将五个字符存储到一个整数中。不止于此,它不适合。

【讨论】:

    【解决方案5】:

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

    【讨论】:

      【解决方案6】:

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

      Dog 可能是 30,3(15),101(7) 或 782,而 God 可能是 33,3(15),101(4) 或 482。比生成的唯一字符串更重要的是,如果保留原始数字,例如 30(782) 对某些 12(782) 来说是唯一的,以便区分类似的字符串,如果您曾经设法了解唯一的可能性。狗永远是狗,但永远不会是猫或老鼠。

      【讨论】:

        猜你喜欢
        • 2011-01-12
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-09-24
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多