Ruby 两个整数的唯一对

Ruby 两个整数的唯一对,ruby,database,crc32,Ruby,Database,Crc32,可能重复: 我正在尝试为两个整数对(Ruby)创建唯一标识符: 那么,i1+i2,i1*i2,i1^i2-不是唯一的,以及(i1>i2)?“i1”+“i2”:“i2”+“i1” 我认为以下解决方案可以: (i1>i2) ? "i1" + "_" + "i2" : "i2" + "_" + "i1" 但是: 我必须将结果保存在DB中并对其进行索引。所以我希望它是一个整数,并且尽可能小 crc32(f(i1,i2))能保证唯一性吗 谢谢 UPD: 实际上,我不确定结果一定是整数。也许我可以

可能重复:

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

那么,i1+i2,i1*i2,i1^i2-不是唯一的,以及(i1>i2)?“i1”+“i2”:“i2”+“i1”

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

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

  • 我必须将结果保存在DB中并对其进行索引。所以我希望它是一个整数,并且尽可能小
  • crc32(f(i1,i2))能保证唯一性吗
  • 谢谢

    UPD:

    实际上,我不确定结果一定是整数。也许我可以把它转换成十进制: (i1>i2)?i1.i2:i2.i1


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

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

  • 有一个即使偶尔发生碰撞也能正常工作的系统
  • 检查碰撞情况,并使用某种类型的重新碰撞
  • 使用1:1映射解决问题的一个显而易见的方法是,需要知道其中一个整数的最大值。只需将一个值乘以最大值,然后将另一个值相加,或者确定两个上限的幂,相应地移动一个值,然后或在另一个值中移动。无论哪种方式,每一位都是为一个或另一个整数保留的。这可能满足您的“尽可能小”要求,也可能不满足

    您的#########字符串每对都是唯一的;如果您可以将其存储为一个字符串,那么您就赢了。

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


    如果i1和i2也是32位数字,那么它们的组合比存储在32位数字(由CRC32返回)中的组合多得多。

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

    unique_id = (max_i2+1)*i1 + i2
    
    如果整数可以是负数,或者永远不会低于某个正整数,则需要最大值和最小值:

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

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

    您要查找的称为a

    中的下图清楚地显示了其工作原理:

    在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位数据类型才能存储所有可能的组合。)

    。我的回答

    哦,等等,我确实犯了一个小错误;更新代码最大值在我的例子中是一个Mysql BIGINT最大值。如果超过最大BIGINT值,我如何保存将在DB中获得的密钥?您是否有过BIGINT范围顶部的数字?如果是这样的话,你只需要使用一个字符串连接方法,比如“#{i1}{u35;{i2}”,因为没有办法对此进行优化。但是如果存在某种较小的最大范围,那么总有一种方法。那就是,你的值真的会达到9223372036854775807吗?九千五百万?如果他们只进入百万或低十亿,这个方法会起作用。我不认为我会达到最大的BIGINT,但我不知道我的最大值。所以可能带分隔符的字符串是最佳解决方案…正如我在其他答案中所评论的。。。这会生成太大的值,无法作为DB中的键。也许只是作为字符串离开(i1>i2)?“i1”+“+”i2:“i2”+“+”i1”是最佳值?添加到最大值将不起作用。它需要倍增。哦,是的。答案已更新。康托对(123123123123321321)=98765432098765778111444778111a
    b
    之间的鸿沟扩大时,康托函数获胜。但这是一个特殊的情况。我不认为一种方法对每一点都更好。但在一定范围内,比如说0到10000,铃木获胜。所以一般来说最好使用铃木函数。还要注意的是,铃木函数将结果打包在一个狭小的空间中,因为康托函数分布在一个大区域内。。
    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]]