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

Sko*_*der 11 .net c# random unique

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

谢谢

Arm*_*yan 13

获取50个元素{1, 2, 3, .... 50} 的数组:使用随机混洗数组的任何标准算法对数组进行混洗.修改后的数组的前六个元素就是您要寻找的.HTH

  • @armen:正确的解决方案是另一回事,好的解决方案是另一回事.你可以写一个随机生成器作为这个问题提到的问题!但那可能不是解决方案. (2认同)

pax*_*blo 10

对于6比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)
Run Code Online (Sandbox Code Playgroud)

然而,这将打破当您从6 -从50到48,从50或6-从-6移动,因为重复开始越来越更有可能.那是因为可用数字池变得越来越小,你最终会丢掉越来越多的东西.

对于一个非常有效的解决方案,让你与你的价值观的一个子集可能重复的(并没有不必要的前期排序),费雪耶茨是要走的路.

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]
Run Code Online (Sandbox Code Playgroud)

只需从池中选择一个随机数,用该池中的顶部数字替换它,然后减小池的大小,就可以得到一个洗牌,而不必担心前面的大量交换.

如果数量很高,这很重要,因为它不会引入不必要的启动延迟.

例如,检查以下基准检查,选择10比10:

<------ 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
Run Code Online (Sandbox Code Playgroud)

您可以随时查看游泳池的减少情况,因为您总是将未使用的游泳池替换为未使用的游泳池,因此您永远不会重复游戏.

使用从其返回的结果作为索引到您的集合中将保证不会选择重复的项目.


Eri*_*ips 6

对于大量唯一数字,请将它们放在List中.

        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);
        }
Run Code Online (Sandbox Code Playgroud)

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

  • 从List中删除数字(无论你想要使用什么`IEnumerable`)都会使它变得独一无二,如果它不存在,你就无法从列表中获取它...再次,这对于LARGE唯一数字集来说更快,因为你不是在寻找可能存在或不存在的数字. (2认同)

ViP*_*uL5 5

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

该数组将包含0到4的5个随机数.

要么

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

该数组将包含0到10之间的5个随机数.

int firstNumber = intArray[0];
int secondNumber = intArray[1];
int thirdNumber = intArray[2];
int fourthNumber = intArray[3];
int fifthNumber = intArray[4];
Run Code Online (Sandbox Code Playgroud)