【问题标题】:Avoiding random duplicates避免随机重复
【发布时间】:2012-11-02 13:00:52
【问题描述】:
System.Random generator = new Random(DateTime.Now.Millisecond);
int[] lotteryNumber = new int[7];

Console.WriteLine("Your lottery numbers: ");
for (int i = 0; i<7; i++)
{
    lotteryNumber[i] = generator.Next(1, 37);
    Console.Write("{0} ",lotteryNumber[i]);
}
Console.ReadLine();

我需要制作一个打印 7 个彩票号码但没有重复号码的程序。上面的代码打印了 (1-37) 范围内的 7 个随机数,但重复了 appaer。我需要一种方法来防止出现重复的数字。

【问题讨论】:

  • @PLB: 或者简单地洗牌。

标签: c# arrays


【解决方案1】:

IMO 最简单的方法是生成一个由所有个可能的数字组成的序列(即 1-37),打乱集合,然后取前七个结果。

在 Stack Overflow 上搜索“Fisher-Yates shuffle C#”会找到很多示例。

实际上,您可以修改 Fisher-Yates shuffle 以在获取结果时产生结果,因此您可以编写如下方法:

var numbers = Enumerable.Range(1, 37).Shuffle().Take(7).ToList();

【讨论】:

    【解决方案2】:

    您可以使用字典,但要确保防止重复键插入。字典的键将作为您需要的唯一数字

    【讨论】:

    • 这种方法会有明显的开销,但在消除重复性方面是万无一失的。
    【解决方案3】:

    您可以将它们扔进HashSet&lt;int&gt;。如果你Add返回false,生成一个新号码。

    【讨论】:

      【解决方案4】:

      如果您尝试从一个范围内不重复地选择数字,您需要创建一个包含所有可能数字的数组,然后“随机播放”一个随机选择:

      int[] allPossibleNumbers = Enumerable.Range(1, 37).ToArray();
      int[] lotteryNumber = new int[7];
      for (int i = 0; i < 7; i++)
      {
          int index = r.Next(i, 37);
          lotteryNumber[i] = allPossibleNumbers[index];
          allPossibleNumbers[index] = allPossibleNumbers[i];
          // This step not necessary, but allows you to reuse allPossibleNumbers
          // rather than generating a fresh one every time.
          // allPossibleNumbers[i] = lotteryNumber[i];
      }
      

      【讨论】:

      • 谢谢,这就像一个魅力!我还没有了解你写的第一句代码。 “Enumerable.Range(1, 37).ToArray();”部分,所以我想必须有另一种方法来实现同样的目标。
      • 你可以做int[] allPossibleNumbers = new int[] { 1, 2, 3, 4, 5, /*yawn */, 36, 37 }; - 我的只是懒惰的版本。
      【解决方案5】:

      生成一个包含 37 项的列表。 然后在你的for中,选择一个并删除选中的

      【讨论】:

        【解决方案6】:

        也许这会有所帮助,如果您获得现有号码,只需尝试找到不在数组中的新号码:

        static void Main(string[] args)
                {
                    System.Random generator = new Random(DateTime.Now.Millisecond); int[] lotteryNumber = new int[7];
        
                    Console.WriteLine("Your lottery numbers: ");
                    for (int i = 0; i < 7; i++)
                    {
                        int lNumber = 0;
                        do
                        {
                            lNumber = generator.Next(1, 37);
                        }
                        while (lotteryNumber.Contains(lNumber));
                        lotteryNumber[i] = lNumber;
        
                        Console.Write("{0} ", lotteryNumber[i]);
                    }
                    Console.ReadLine();
                }
        

        【讨论】:

          【解决方案7】:
          HashSet<int> set = new HashSet<int>();
          System.Random generator = new Random(DateTime.Now.Millisecond);
          
          while(set.Count < 7){
              set.Add(generator.Next(1,37);
          }
          

          这应该可以,因为 HashSet 会自动忽略重复项。只需循环直到集合达到您需要的单位数量。唯一潜在的问题是它有可能(不太可能)循环很长时间,但它最终应该会响应。

          【讨论】:

            【解决方案8】:

            所以我使用了您的原始代码...发现了一些逻辑错误并添加了您正在寻找的修复程序以防止随机数重复。

            享受吧!

             System.Random generator = new Random(DateTime.Now.Millisecond);
                        int[] lotteryNumber = new int[7];
                        int lowerBounds = 1;
                        int upperBounds = 8;
                        int maxNumberLotteryValues = 7;
            
                        if ( ( upperBounds - lowerBounds ) < (maxNumberLotteryValues))
                        {
                            Console.Write("Warning: Adjust your upper and lower bounds...there are not enough values to create a unique set of Lottery numbers! ");
            
                        }
                        else
                        {
                            Console.WriteLine("Your lottery numbers: ");
                            for (int i = 0; i < maxNumberLotteryValues; i++)
                            {
                                int nextNumber = generator.Next(lowerBounds, upperBounds);
                                int count = lowerBounds;  //Prevent infinite loop
            
                                while ((lotteryNumber.Contains(nextNumber))
                                    && (count <= upperBounds))
                                {
                                    nextNumber = generator.Next(lowerBounds, upperBounds);
                                    count++;  //Prevent infinite loop
                                }
            
                                lotteryNumber[i] = nextNumber;
                                Console.Write("{0} ", lotteryNumber[i]);
                            }
                        }
            
                        Console.ReadLine();
            

            【讨论】:

              【解决方案9】:
              const int nBalls = 37;
              const int nPicks = 6;
              int[] balls = new int[nPicks];
              Random rnd = new Random(DateTime.Now.Millisecond);
              
              int remainingBalls=nBalls;
              int remainingPicks=nPicks;
              for (int i = 1; i <= nBalls; i++)
              {
                  if (rnd.Next(1, remainingBalls+1) <= remainingPicks)
                      balls[--remainingPicks]=i;
                  remainingBalls--;
              }
              
              Console.WriteLine(string.Join(",",balls));
              

              随着 nPicks/nBalls 变大,将优于 Shuffle 和 HashSet 方法。

              【讨论】:

                猜你喜欢
                • 2023-03-23
                • 2019-06-15
                • 1970-01-01
                • 2017-12-26
                • 2014-02-05
                • 1970-01-01
                • 2010-12-19
                • 1970-01-01
                • 1970-01-01
                相关资源
                最近更新 更多