在一个范围内生成N个随机和唯一的数字

使用C#在给定范围内生成N个唯一数字的有效方法是什么? 例如,在1到50之间生成6个唯一的数字。懒惰的方法是简单地在一个循环中使用Random.Next() ,并将该数字存储在数组/列表中,然后重复并检查它是否已经存在或不存在等。有没有更好的方法来生成一组随机但唯一的数字? 为了添加更多的上下文,我想从集合中selectN个随机项目,使用它们的索引。

谢谢

以50个元素组成的数组: {1, 2, 3, .... 50}使用任意随机混排数组的标准algorithm来对数组进行混洗。 修改数组的前六个元素就是你正在寻找的东西。 HTH

对于从50岁以后的6人来说,我不太确定我是否担心效率,因为重复的几率相对较低(从我的后面的计算来看总体上是30%)。 你可以很容易地记住你生成的以前的数字并把它们扔掉,就像(伪代码)一样:

 n[0] = rnd(50) for each i in 1..5: n[i] = n[0] while n[1] == n[0]: n[1] = rnd(50) while n[2] == any of (n[0], n[1]): n[2] = rnd(50) while n[3] == any of (n[0], n[1], n[2]): n[3] = rnd(50) while n[4] == any of (n[0], n[1], n[2], n[3]): n[4] = rnd(50) while n[5] == any of (n[0], n[1], n[2], n[3], n[4]): n[5] = rnd(50) 

然而,当你从五十分之六移到四十分之五十,或者六分之六时,这将会失败,因为重复的结果开始变得更可能。 这是因为可用数字池变小了,最终你会越来越多地扔掉。

对于一个非常有效的解决scheme,给你的值的一个子集与重复的可能性(没有不必要的前期sorting),费希尔耶茨是要走的路。

 dim n[50] // gives n[0] through n[9] for each i in 0..49: n[i] = i // initialise them to their indexes nsize = 50 // starting pool size do 6 times: i = rnd(nsize) // give a number between 0 and nsize-1 print n[i] nsize = nsize - 1 // these two lines effectively remove the used number n[i] = n[nsize] 

通过简单地从池中select一个随机数,将其replace为该池中的最大数字,然后减小池的大小,就可以进行洗牌而不必担心大量的交换。

如果这个数字很高,那么它不会引起不必要的启动延迟。

例如,检查下面的基准检查,从10select10:

 <------ n[] ------> 0 1 2 3 4 5 6 7 8 9 nsize rnd(nsize) output ------------------- ----- ---------- ------ 0 1 2 3 4 5 6 7 8 9 10 4 4 0 1 2 3 9 5 6 7 8 9 7 7 0 1 2 3 9 5 6 8 8 2 2 0 1 8 3 9 5 6 7 6 6 0 1 8 3 9 5 6 0 0 5 1 8 3 9 5 2 8 5 1 9 3 4 1 1 5 3 9 3 0 5 9 3 2 1 3 9 1 0 9 

你可以看到游泳池减less,因为你总是用一个未使用的更换旧的,你永远不会重复。

使用从那里返回的结果作为索引到你的集合将保证没有重复的项目将被选中。

对于大量的独特数字,把它们放在一个列表中..

  Random random = new Random(); List<int> uniqueInts = new List<int>(10000); List<int> ranInts = new List<int>(500); for (int i = 1; i < 10000; i++) { uniqueInts.Add(i); } for (int i = 1; i < 500; i++) { int index = random.Next(uniqueInts.Count) + 1; ranInts.Add(uniqueInts[index]); uniqueInts.RemoveAt(index); } 

然后随机生成一个从1到myInts.Count的数字。 存储myInt值并将其从列表中删除。 不需要拖动列表,也不需要查看该值是否已经存在。

 var random = new Random(); var intArray = Enumerable.Range(0, 4).OrderBy(t => random.Next()).ToArray(); 

这个数组将包含从0到4的5个随机数。

要么

  var intArray = Enumerable.Range(0, 10).OrderBy(t => random.Next()).Take(5).ToArray(); 

这个数组将包含0到10之间的5个随机数。

 int firstNumber = intArray[0]; int secondNumber = intArray[1]; int thirdNumber = intArray[2]; int fourthNumber = intArray[3]; int fifthNumber = intArray[4]; 

而不是使用List使用Dictionary

从1到40生成唯一的随机号码:

输出确认:

 class Program { static int[] a = new int[40]; static Random r = new Random(); static bool b; static void Main(string[] args) { int t; for (int i = 0; i < 20; i++) { lab: t = r.Next(1, 40); for(int j=0;j<20;j++) { if (a[j] == t) { goto lab; } } a[i] = t; Console.WriteLine(a[i]); } Console.Read(); } } 

样本输出:

7 38 14 18 13 29 28 26 22 8 24 19 35 39 33 32 20 2 15 37