4

我想随机取 50 个数字,这样就不能使用随机方法重复它们。

到目前为止,以下是我的代码:

private void settext()
{      
     int i;
     Queue <int> qe= new Queue<int>(50);
     Random rm= new Random();
     for (int g = 0; g < 50; g++)
     {
         i = rm.Next(1, 50);
         if (!qe.Contains(i))
         {
              qe.Enqueue(i);
         }                
     }
 }
4

5 回答 5

6

我建议不要循环直到找到一个尚未使用的数字,而是创建一个包含 50 个可能数字的列表(或数组),然后对其进行洗牌。然后,您可以随心所欲地选择其中的数量。

Stack Overflow 上有很多洗牌问题,比如这个

这样做的好处是性能是完全可预测的和线性的 - 而如果你从 50 个数字中取出所有 50 个数字,最后你将不得不继续生成随机数,直到你碰巧得到最后一个。对 50 来说还不错,但想象一下,如果你有数十万个数字......

(另请注意,您现有的代码在任何地方都没有使用数字 20,如果您尝试仅生成 20 个数字,这应该会敲响警钟......)

于 2012-12-25T09:18:10.140 回答
1

您的代码唯一的问题是,如果发现重复项,您仍在增加循环并且没有获得队列中的所有值(50)。您可以使用 while 循环,并且仅在找到非重复值时才增加索引。

int index=0;
int i;
Queue<int> qe = new Queue<int>(50);
Random rm = new Random();
while(index< 50)
{
    i = rm.Next(1, 51); //to get from 1 to 50
    if (!qe.Contains(i)) //to check for duplicate
    {
        qe.Enqueue(i);
        ++index;
    }

}

以上将生成 50 个唯一的随机数,如果您想从中获取 20 个数字,则:

var numbers = qe.Take(20);
于 2012-12-25T09:13:38.693 回答
1

我认为,你强迫它找到 50 个不同的数字,同时只允许它从 49 个可能的数字范围内生成它们。试试rm.Next(50) + 1吧。

于 2012-12-25T09:15:55.663 回答
1

使用 Linq 怎么样?

private static Random rand = new Random();

var twentyUniqueNumbers = RandomNumberStream().Distinct().Take(20);

IEnumerable<int> RandomNumberStream()
{
  yield return rand.Next(1,50);
}

或者更好的是,创建一个包含 50 个数字的列表,然后随机播放 20 个 ...

var twentyUniqueNumbers = Enumerable.Range(0,50)
                                    .OrderBy(s => rand.Next());
                                    .Take(20);

这将提供更可预测的性能。

于 2012-12-25T09:17:39.833 回答
0

按照您的逻辑,编写此代码可能更简单:

var results = new HashSet<int>();
var random = new Random();
while (results.Count < 20)
{
    results.Add(random.Next(1, 50));
};

无需检查数字是否已添加到哈希集中,因为每个数字只会添加一次...

但是...这只是一个快速解决方案,可以帮助您理解您要解决的问题,(基本上是教室示例)但是您应该真正接受 Jon Skeet 提供的建议,因为您不知道需要多长时间它实际上需要执行上面的代码。

需要注意的另一件事是,您正在使用 Queue 类,该类旨在像 FIFO 缓冲区一样使用......这并不真正适用于您的问题。

于 2012-12-25T15:51:19.027 回答