如何在一个范围内生成一个随机数但排除一些?

时间:2011-06-22 16:17:39

标签: java random

如何在一个范围内生成随机数但排除一些,而不继续生成并检查生成的数字是否是我要排除的数字之一?

8 个答案:

答案 0 :(得分:43)

每次随机无重生的一种可能解决方案是使用以下算法:

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(包括两者)之间生成一个随机数(int),并且不会为您提供数组exclude中包含的任何数字。所有其他数字的概率相等。请注意,必须保留以下约束:exclude按升序排序,所有数字都在提供的范围内,并且所有数字都相互不同。

答案 1 :(得分:15)

/**
 * @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;
}

这个想法是将生成随机数的范围缩小到开始和结束之间的差减去该范围内被排除的数字的数量。

因此,您获得的范围长度与可能的有效数字的数量相同。换句话说:你已经从范围中移除了所有洞。

生成随机数后,您需要将“孔”放回范围内。只要排除的数字低于或等于生成的数字,就可以通过递增生成的数字来实现这一点。较低的排除数是在生成的数字之前的范围内的“空洞”。并且在该数字之前,每个洞的生成数字都会向右移动。

答案 2 :(得分:3)

您可以按照随机数字排除的最佳方法,排除某些数字,然后选择您想要的数字,然后随机选择所选的数字。例如,在伪代码中:

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;
}

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

答案 3 :(得分:2)

我认为另外一个问题是:你想要排除什么数字?它们代表某种范围还是完全随机

如果您想忽略的是一系列数字,您可以从几个仅代表有效数字的集合中生成随机数:

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

通过这种方式,您确定永远不会选择排除:&lt; 0,10,11,12,13,14,20,21,&gt; 27

然后,当你得到3个数字时,你可以再次随机选择其中一个。

如果排除的数字到处都是,我担心每次都要对某些被排除的数字进行检查。

答案 4 :(得分:1)

创建一个地图,该地图接受一个没有范围限制的随机函数的输出,并将其映射到您想要的限制范围。

例如,如果我想要一个1-10的随机int但是从来没有7我可以这样做:

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

只要您确保映射为1:1,就可以避免扭曲rand函数的随机性。

答案 5 :(得分:0)

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

答案 6 :(得分:0)

可以起作用并且适用于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

此致  斯特凡

答案 7 :(得分:0)

排除数字应该在范围参数

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;
}