给定n个自然数从0开始,b
是0到n之间的数字
我希望随机选择一个不包括b
的数字。
说n是5
那么要选择的数字是{0,1,2,3,4,5}
说b是4,
然后我的随机选择来自{0,1,2,3,5}
执行此操作的方法是执行while循环,直到random.nextInteger()找不到4。
除了使用while循环之外,还有其他方法吗?
答案 0 :(得分:2)
我会写一个简单的扩展名:
// N.B. : min is inclusive, max is exclusive; so range is: [min,max) - {toExclude}
public static int Next(this Random rand, int min, int max, int toExclude)
{
int v = rand.Next(min, max - 1);
if (v < toExclude)
return v;
return v + 1;
}
用法:
var random = new Random();
var val = random.Next(0,6,4); // 6 because max is exclusive in C# random.Next()
答案 1 :(得分:0)
你的方法在我的选择中是最好的。它简单而优雅,即使对于m=2
,它平均为O(1)
(预期的重绘次数为1/2 + 1/4 + 1/8 + .... < 1
)。
如果你想避免无限循环的最坏情况,有另一种选择,但我怀疑它会产生真正的性能影响。
d
。如果d < b/m
:在范围[0,b)中绘制一个数字并将其返回。d > b/m
) - 在范围[b+1,m]
中绘制一个随机数并将其返回。注意,它确实是均匀分布的,因为:
m+1
范围内有0,...,m
个数字,但只有m
&#34;有效&#34;数字(不包括b
)。
在b
范围内有0,1,...,b-1
个数字 - 因此,假设均匀分布的数字在此范围内的概率为b/m
- 这正是P(d < b/m)
。< / p>
在java中它看起来类似于:
int m = 5, b = 4;
Random r = new Random();
double d = r.nextDouble();
if (d < ((double)b)/m) {
System.out.println(r.nextInt(b));
} else {
System.out.println(r.nextInt(m-b) + b + 1);
}
答案 2 :(得分:0)
如果你愿意,这是另一种方法:
import random
def random_unifrom(n,b):
assert b < n and n > 0 and b > 0
nMinusOneList = [i for i in range(n) if i != b]
lSize = len(nMinusOneList)
randIndex = random.randint(0, lSize-1)
return nMinusOneList[randIndex]
为了简单起见,我在python中写了这个。 创建nMinusOneList具有O(n)的复杂性。 返回随机索引的复杂性取决于您使用的随机函数。
最后,如果你采用这种方法而不是while循环,你什么都不会丢失,但即使你使用while循环方法,如果随机函数是随机的(!!)那么你应该没有问题。但是,我上面的方法从一开始就排除了你不需要的数字。
在C#中,我在python中使用的一行可能是几行,它们包含0到n范围内的for循环,条件是x(for循环索引)不等于b,in建立列表,然后你将有一个排除b。
的列表