我怎样才能产生一个范围内的随机数字,但排除一些?

我怎样才能在一个范围内生成一个随机数,但排除一些,而不会继续生成,并检查生成的数字是否是我想排除的数字之一?

一个可能的解决scheme是不使每次随机再生的,就是使用下面的algorithm:

public int getRandomWithExclusion(Random rnd, int start, int end, int... exclude) { int random = start + rnd.nextInt(end - start + 1 - exclude.length); for (int ex : exclude) { if (random < ex) { break; } random++; } return random; } 

这个方法可以用一个数组引用来调用,例如

 int[] ex = { 2, 5, 6 }; val = getRandomWithExclusion(rnd, 1, 10, ex) 

或者直接在号码中插入号码:

 val = getRandomWithExclusion(rnd, 1, 10, 2, 5, 6) 

它会在startend (包括end )之间生成一个随机数(int),并且不会给出包含在数组exclude中的任何数字。 所有其他数字以相等的概率出现。 请注意,以下约束条件必须成立: exclude按升序sorting,所有数字均在所提供的范围内,且所有数字都相互不同。

 /** * @param start start of range (inclusive) * @param end end of range (exclusive) * @param excludes numbers to exclude (= numbers you do not want) * @return the random number within start-end but not one of excludes */ public static int nextIntInRangeButExclude(int start, int end, int... excludes){ int rangeLength = end - start - excludes.length; int randomInt = RANDOM.nextInt(rangeLength) + start; for(int i = 0; i < excludes.length; i++) { if(excludes[i] > randomInt) { return randomInt; } randomInt++; } return randomInt; } 

这个想法是将产生随机数的范围减小到开始与结束之间的差值,减去排除在该范围内的数字的计数。

所以你得到一个与可能的有效数字相同的范围长度。 换句话说:你已经从范围中删除了所有的洞。

在生成随机数后,您必须将“洞”放回到范围内。 只要排除的数字小于或等于生成的数字,就可以通过增加生成的数字来实现。 较低的排除号码是生成的号码之前的范围中的“孔”。 然后生成的数字在该数字前面的每个孔都右移。

最好的方法,你可以按照随机化的数字,不包括一些select你想要的数字,然后随机select数字。 例如,在伪代码中:

 List<Number> numbers; numbers.add(1); numbers.add(2); numbers.add(3); //You can do a "for" without adding the excluded numbers.. //Then, your randomizer could be... public Number getRandoNumber() { int index = Random.get(0, numbers.size()); return numbers.get(index); } 

现在,您不需要检查“生成的数字”是否被允许,因为它根本不存在。

如果你不想让他们重复,你可以这样做:

 Collections.shuffle(numbers); public Number getRandomNotRepeat() { if(numbers.size() == 0) throw new RuntimeException("No more numbers"); Number n = numbers.get(0); numbers.removeFirst(); return n; } 

这是所有的伪代码,不要复制和粘贴!

我想另一个问题是:你想要的数字是多less? 他们代表某种范围,还是完全随机

如果这是一个您想要忽略的数字范围,您可以从几个只能表示有效数字的随机数中生成随机数:

 rand(1,9); rand(15,19); rand(22,26); 

这样你就可以肯定你永远不会select排除:<0,10,11,12,13,14,20,21,> 27

然后,当你得到你的3号码,你可以再次随机select其中的一个。

如果被排除的数字遍布整个地方,恐怕每次都要检查一下排除的数字。

创build一个没有范围限制的随机函数输出的映射,并将其映射到您想要的范围内并加以限制。

例如,如果我想从1到10的随机int,但从来没有7我可以做这样的事情:

 int i = rand(1, 9); if i>=7 i++; return i; 

只要确保映射为1:1,就可以避免使rand函数的随机性发生偏差。

根据你排除的随机数列表有多大,我只会生成你的数字,并检查它是否在排除的数字数组中,如果是,就丢弃它。 我知道你不想每次都检查,但除了明确指定范围之外,我想不出另外一种方法,如果你排除了5个以上的数字,可能会更糟糕。

一些可以工作并适用于int和double数字的东西可能是这样的:

 public int getRandomNumberWithExclusion( int start, int end ) { Random r = new Random(); int result = -1; do { result = start + r.nextInt( end - start ); }//do while( !isAllowed( result ) ); return result; }//met private boolean isAllowed( int number ) { //your test for restricted values here }//met 

问候,Stéphane

排除号码应在范围参数中

 private int GiveMeANumber(int range,int... exclude) { Set<Integer> integers=new HashSet<>(); int count=range; for(int i=0;i<count;i++) integers.add(i); integers.removeAll(Arrays.asList(exclude)); int index = new Random().nextInt(range - exclude.length); count=0; for (int value:integers){ if(count==index) return value; count++; } return 0; }