【问题标题】:How do i deterministically generate n unique numbers within a range from a GUID? [closed]如何从 GUID 确定性地生成一个范围内的 n 个唯一数字? [关闭]
【发布时间】:2018-06-22 19:25:07
【问题描述】:

一个具体的例子。

如果我的范围为 1-300,如何使用 GUID "EDAAE218-FBF0-4B66-AEAF-FB036FBF69F4" 在该范围内生成 5 个唯一数字。对 GUID 应用相同的算法应该会导致每次都选择相同的 5 个数字。

输入不必是 GUID,它只是充当某种键。

我试图解决的问题的一些背景。我有一个硬编码的值列表,其中包含大约 300 个左右的元素。我正在尝试找到一种方法来从该列表中选择 20 个始终产生相同元素的元素。

我的想法是生成一个可以分发给多个用户的 GUID。当这些用户将 GUID 输入应用程序时,将为每个人返回相同的 20 个元素。

【问题讨论】:

  • 当您将确定性和随机性放在同一个句子中时,似乎有些不对劲。
  • 如果总是相同的输出怎么随机?
  • 只要在需要盐键的地方使用任何散列算法。 GUID 将用作盐。具体之一是使用 bcrypt hash
  • 对不起,我的描述很混乱。我已经更新了问题并为问题提供了一些背景信息。
  • GUID 不是我的首选——它们应该是唯一的而不是随机的。您可能正在寻找 Mersenne Twister

标签: c# algorithm random


【解决方案1】:

guid 实际上是一个 128 位的数字。因此,只要表示您的数字所需的位数少于 guid (128) 中的位数,您就可以轻松地做到这一点。您不需要散列 guid 或类似的东西。

编辑:

现在我知道您需要什么(即从 guid 派生的唯一种子,您可以这样做) - 但您同样可以分发一个 32 位数字并避免 guid 到 int 的转换.

EDIT2:根据上面 cmets 的建议使用 GetHashCode。

编辑 3:生成唯一编号。

 static void Main(string[] args)
 {
     var guid = new Guid("bdc39e63-5947-4704-9e12-ec66c8773742");
     Console.WriteLine(guid);
     var numbers = FindNumbersFromGuid(guid, 16, 8);

     Console.WriteLine("Numbers: ");
     foreach (var elem in numbers)
     {
         Console.WriteLine(elem);
     }
     Console.ReadKey();
 }

 private static int[] FindNumbersFromGuid(Guid input,
     int maxNumber, int numberCount)
 {
     if (numberCount > maxNumber / 2) throw new ArgumentException("Choosing too many numbers.");
     var seed = input.GetHashCode();
     var random = new Random(seed);
     var chosenSoFar = new HashSet<int>();
     return Enumerable.Range(0, numberCount)
         .Select(e =>
         {
             var ret = random.Next(0, maxNumber);
             while (chosenSoFar.Contains(ret))
             {
                 ret = random.Next(0, maxNumber);
             }
             chosenSoFar.Add(ret);
             return ret;
         }).ToArray();
 }

【讨论】:

  • return Enumerable.Range(0, numberCount) .Select(e =&gt; random.Next(0, maxNumber)).ToArray(); 很容易产生重复值。
  • 另外,您的算法仅使用 GUID 的前 4 个字节,而丢弃其他 12 个字节。
  • 改为使用 GetHashCode,它将散列所有 16 个字节。另一种选择可能是初始化 4 个 Random 实例,然后将这些值散列在一起,从而使用 GUID 的所有 16 个字节。不过,从 OP 的要求来看,这就足够了。
  • 好的,但这是我指出的两个问题中较小的一个,较大的是 它可以经常产生非唯一值(这个问题的标题特别声明 OP 想要唯一的值)。例如,使用 GUID 721550ec-b930-4099-a399-34432f102eb8 运行代码会生成值 148148、141、132 和 22。
  • 已修复。现在产生唯一的数字。
猜你喜欢
  • 2011-05-16
  • 2018-12-17
  • 2014-05-15
  • 2011-08-02
  • 2012-08-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多