为什么我得到重复

本文关键字:为什么 | 更新日期: 2023-09-27 18:00:33

我制作了一个Keno游戏,它从数组列表NumbersToPickFrom中随机抽取20个数字。我生成一个随机数,然后检查该数字当前是否在可供选择的数字中。如果是,我会把它添加到我的号码数组中,这些号码将被用作彩票号码,随机选择,然后我会从可用号码中删除它。如果它不在列表中,那就意味着它已经被选中了,我需要一个新号码。我用goto重新开始。我以为它运行良好,但似乎我一直在复制。我是否使用了ArrayList.Remove函数?如果它被删除了,我就不应该在我最后的随机选择列表中得到重复。如果有人能看到我遗漏了什么,那将是有帮助的。下面的代码就是我所说的代码。

private void GeneratePicks()
    {
        for (int i = 1; i <= 20; )
        {
        Retry:
            int rInt = GenerateRandomPick();
            if (NumbersToPickFrom.Contains(rInt))
            {
                RandomPicks.Add(rInt);
                NumbersToPickFrom.Remove(rInt);
                i++;
                //PickBox.Text += rInt + " ,";
                RandomPicks.Sort();
            }
            else
            {
                goto Retry;
            }
        }
    }
    private int GenerateRandomPick()
    {
        int rInt = rand.Next(1,81);
        return rInt;
    }
    private void initializeArray()
    {
        for (int i = 1; i <= 80; i++)
        {
            NumbersToPickFrom.Add(i);
        }
    }

为什么我得到重复

我运行了您的代码,没有得到任何重复。

尽管如此,反复挑选随机数字并与缩小的列表进行比较的方法并不是最好的方法。

试试这个:

RandomPicks =
    Enumerable
        .Range(1, 80)
        .OrderBy(n => rand.Next())
        .Take(20)
        .OrderBy(n => n)
        .ToList();

我发现您的代码运行良好。

我添加了以下公共变量,使其工作(在我的机器上)

   List<int> NumbersToPickFrom = new List<int>();
   List<int> RandomPicks = new List<int>();
   Random rand = new Random();

虽然在第二次运行时,我发现RandomPicks中的项目数量翻了一番,而且还有重复项,所以我将initializeArray()更改为

   private void initializeArray()
   {
       for (int i = 1; i <= 80; i++)
       {
           NumbersToPickFrom.Add(i);
       }
       RandomPicks.Clear();    // Added this to clear the existing values in the list.
   }

如果你想"老派"做这件事,并实际观察发生了什么,请将GeneratePicks()方法更改为:

private void GeneratePicks()
{
    RandomPicks = new List<int>();
    initializeArray();
    for (int i = 0; i < 20; ++i)
    {
        int randomIndex = rand.Next(1, 80 - i);
        int randomPick = NumbersToPickFrom[randomIndex];
        RandomPicks.Add(randomPick);
        NumbersToPickFrom[randomIndex] = NumbersToPickFrom[80 - i - 1];
    }
    RandomPicks.Sort();
}

这将运行整整20次,并保证不重复。

我在您的代码中看不到任何错误,并通过运行100000次测试了您的代码,没有得到任何重复。

然而,有更好的方法来获得随机数。一个简单的改进是从NumbersToPickFrom列表中随机选择一个数字,而不是只选择一个号码,这样就不需要内部循环了。

有一种更好的方法来挑选彩票号码。您可以循环浏览这些数字,并计算每个数字被选中的概率。数字被拾取的概率是PicksLeft / NumbersLeft,例如,数字1被拾取的可能性是20 / 80,然后概率根据拾取的数字而变化:

private void GeneratePicks() {
  int pick = 20;
  for (int n = 1; pick > 0; n++) {
    if (rand.Next(81 - n) < pick) {
      RandomPicks.Add(n);
      pick--;
    }
  }
}

由于数字是按顺序挑选的,您甚至不必事后对数字进行排序,也不需要NumbersToPickFrom列表。