【问题标题】:Unique pair of two integers [duplicate]唯一的两个整数对[重复]
【发布时间】:2012-12-01 19:03:42
【问题描述】:

可能重复:
Mapping two integers to one, in a unique and deterministic way

我正在尝试为一对两个整数(Ruby)创建唯一标识符:

f(i1,i2) = f(i2, i1) = some_unique_value

所以,i1+i2, i1*i2, i1^i2 - 和 (i1>i2) 一样不是唯一的? “i1”+“i2”:“i2”+“i1”。

我认为以下解决方案可以:

(i1>i2) ? "i1" + "_" + "i2" : "i2" + "_" + "i1"

但是:

  1. 我必须将结果保存在数据库中并为其编制索引。所以我更喜欢它是一个整数,并且尽可能的小。
  2. Zlib.crc32(f(i1,i2)) 能保证唯一性吗?

谢谢。

更新:

实际上,我不确定结果是否必须是整数。也许我可以将其转换为十进制: (i1>i2) ? i1.i2 : i2.i1

?

【问题讨论】:

    标签: ruby database crc32


    【解决方案1】:

    您要查找的内容称为Pairing function

    German wikipedia page 的下图清楚地展示了它的工作原理:

    在 Ruby 中实现:

    def cantor_pairing(n, m)
        (n + m) * (n + m + 1) / 2 + m
    end
    
    (0..5).map do |n|
      (0..5).map do |m|
        cantor_pairing(n, m)
      end
    end
    => [[ 0,  2,  5,  9, 14, 20],
        [ 1,  4,  8, 13, 19, 26],
        [ 3,  7, 12, 18, 25, 33],
        [ 6, 11, 17, 24, 32, 41],
        [10, 16, 23, 31, 40, 50],
        [15, 22, 30, 39, 49, 60]]
    

    请注意,您需要将此配对的结果存储在一个数据类型中,该数据类型的位数与您的两个输入数字加起来的位数一样多。 (如果两个输入数字都是 32 位的,您显然需要一个 64 位的数据类型才能存储所有可能的组合。)

    【讨论】:

      【解决方案2】:

      不,Zlib.crc32(f(i1,i2)) 并非对于 i1 和 i2 的所有整数值都是唯一的。

      如果 i1 和 i2 也是 32 位数字,那么它们的组合比 CRC32 返回的 32 位数字所能存储的要多得多。

      【讨论】:

        【解决方案3】:

        CRC32 不是唯一的,不适合用作键。假设您知道整数 i1i2 的最大值:

        unique_id = (max_i2+1)*i1 + i2
        

        如果您的整数可以是负数,或者永远不会低于某个正整数,则需要最大值和最小值:

        (max_i2-min_i2+1) * (i1-min_i1) + (i2-min_i2)
        

        这将为您提供识别两个整数的绝对最小数字。

        【讨论】:

        • 哦,等等,我确实犯了一个小错误;更新代码
        • 在我的例子中,最大值是 Mysql BIGINT 最大值。如果超过最大 BIGINT 值,如何保存我将在 DB 中获得的密钥?
        • 你会在 bigint 范围的顶部有数字吗?如果是这样,您将不得不使用像“#{i1}_#{i2}”这样的字符串连接方法,因为没有办法围绕它进行优化。但如果有某种更小的最大范围,那么总有办法。
        • 也就是说,你的价值观真的会变得像 9223372036854775807 一样大吗? 9千亿?如果他们只进入数百万或数十亿,这种方法将起作用。
        • 我认为我不会达到 BIGINT 的最大值,但我不知道我的最大值。所以也许带有一些分隔符的字符串是最佳解决方案......
        【解决方案4】:

        好吧,当输入是超过 4 字节的任意二进制字符串时,没有 4 字节哈希是唯一的。您的字符串来自一个高度受限的符号集,因此冲突会更少,但“不,不是唯一的”。

        有两种方法可以使用小于两个整数的可能值范围的整数:

        1. 拥有一个即使偶尔发生碰撞也能正常工作的系统
        2. 检查冲突并使用某种重新散列

        使用 1:1 映射解决问题的明显方法要求您知道其中一个整数的最大值。只需将一个乘以最大值并添加另一个,或者确定两个上限的幂,相应地移动一个值,然后在另一个中进行 OR。无论哪种方式,每一位都为整数中的一个或另一个保留。这可能会也可能不会满足您的“尽可能小”的要求。

        您的###_### 字符串每对都是唯一的;如果您可以将其存储为您获胜的字符串。

        【讨论】:

        • 正如我在其他答案中评论的那样......这会产生太大的价值,无法成为数据库中的关键。也许只是留下字符串 (i1>i2) ? "i1" + "" + "i2" : "i2" + "" + "i1") 是最优的?
        • 添加到最大值不起作用。它需要成倍增加。
        • 哦,呃,我。答案已更新。
        【解决方案5】:

        【讨论】:

        • @Savash 很有趣。显然,当ab 之间的鸿沟扩大时,康托尔函数获胜。但这是一个具体案例。我不认为一种方法对每一点都更好。但是对于一系列值,比如 0 到 10000,铃木胜出。所以一般情况下还是使用铃木的功能比较好。另请注意,Suzuki 函数将结果打包在一个狭小的空间中,因为 Cantor 函数分布在大面积上..
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2021-08-28
        • 2011-05-14
        • 1970-01-01
        • 2020-10-17
        • 2020-05-03
        • 2011-07-03
        • 2016-02-26
        相关资源
        最近更新 更多