【问题标题】:Convert sequence of numbers to random-looking IDs?将数字序列转换为外观随机的 ID?
【发布时间】:2009-04-15 00:48:04
【问题描述】:

我正在开发一个需要生成唯一、非顺序 ID 的应用程序。我的限制之一是它们必须由 3 个数字后跟 2 个字母组成(只有大约 600k 个 ID)。鉴于我的 ID 池相对较小,我正在考虑简单地生成所有可能的 ID,将它们洗牌并将它们放入数据库中。因为,在内部,我将有一个简单的、连续的 ID 可供使用,因此很容易一次将它们取出一个并确保我没有任何重复。

感觉这不是一个非常令人满意的解决方案。有没有人有比这种“抽奖”方法更有趣的从有限池中生成唯一 ID 的方法?

【问题讨论】:

  • 您计划实际使用多少个 ID?生成这么多并存储它们只是为了使用几百个,这将是一种耻辱。
  • 如果它们是连续的,为什么重要?

标签: random


【解决方案1】:

这可以通过多种不同的方式完成,具体取决于您要优化的内容(速度、内存使用情况等)。

ID 模式 = ddd c1c[0]

选项 1(本质上类似于散列,类似于 Zak 的):
1 生成一个介于 0 和可能性数 (676k) 之间的随机数。
2- 将数字转换为组合

    ddd = random / (26^2)
    c[0] = random % (26)
    c[1] = (random / 26) % 26

3- 查询 DB 是否存在 ID 并递增直到找到空闲 ID。

选项2(线性反馈移位寄存器,见wikipedia):
1- 随机数在 (0,676k) 范围内的种子。 (请参阅下面为什么不能使用“0”播种)
2- 通过将以下内容应用于当前 ID 号生成后续随机数

    num = (num >> 1) ^ (-(num & 1u) & 0x90000u);

3- 跳过大于范围的 ID(即 0xA50A0+)
4- 将数字转换为 ID 格式(如上)
*您需要保存最后生成的用于 ID 的数字,但您不需要查询数据库以查看它是否被使用。由于 LFSR 的工作方式,此解决方案将枚举除 [000 AA] 之外的所有可能的 ID。

[edit] 由于您的范围实际上比您需要的大,您可以通过在转换为 ID 之前减去 1 来返回 [000 AA] 并使您的有效范围为 (0,0xA50A0]

【讨论】:

  • 我很好奇。 LFSR 算法是从哪里来的?
【解决方案2】:

使用有限群。基本上,取一个 32 位或 64 位整数,并找到一个与整数最大值互质的大数;调用这个数字 M。然后,对于所有整数 n,n * M 将产生一个具有很多数字的唯一数字。

这样做的好处是您不需要预先填充数据库或运行单独的选择查询——您可以在一个插入语句中完成所有这些操作,只需让您的 n 成为一个自动-递增,并有一个单独的 ID 列,默认为 n * M。

【讨论】:

  • 实际上,如果您并排看到其中两个 ID(或者实际上是任何距离的任何 3 个或更多),您将能够获取您看到的 ID 的 gcd,并且能够准确预测下一个 ID。不幸的是,这个解决方案的熵非常小。此外,这不符合 OP 使用的 3 位 2 字母规范
【解决方案3】:

您可以生成符合该标准的随机 ID,执行 DB 选择以查看它是否已经存在,然后将其插入 DB 以注意它已被“使用”。对于该方案生命周期的前 25%(或大约 150k 个条目),生成新的随机 ID 应该相对较快。不过在那之后,需要的时间会越来越长,您不妨预先填写表格以查找免费 ID。

【讨论】:

  • 您可以将其封装在一个返回未使用 id 的存储过程中。这样你就不会在测试 ID 时反复敲击数据库
【解决方案4】:

根据您对顺序的定义,您可以只选择字母上的某个起点,例如“aa”,然后循环遍历三个数字,所以它是: 001aa 002aa 003aa

一旦你到达 zz 然后增加数字部分。

【讨论】:

    【解决方案5】:

    您可以使用模运算来生成 id。选择一个与 676,000 互质的数字作为种子。 id 是表的标准递增 id。那么下面的伪代码就是你所需要的:

    uidNo = (id * seed) % 676000
    digits = uidNo / 676
    char1 = uidNo % 26
    char2 = (uidNo / 26) % 26
    uidCode = str(digits) + chr(char1+65) + chr(char2+65)
    

    如果用户有多个连续发出的 id,他们可以猜测算法和种子,并按顺序生成所有 id。这可能意味着该算法对于您的用例来说不够安全。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-05-22
      • 2013-08-13
      • 2016-04-20
      • 1970-01-01
      • 1970-01-01
      • 2022-01-26
      相关资源
      最近更新 更多