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

时间:2011-04-02 03:03:42

标签: javascript random numbers

基本上我选择0-24之间的随机数:

Math.floor(Math.random() * myArray.length); // myArray contains 25 items

让我们说它出现了8.现在我想在0-24的相同范围内获得另一个数字,但这一次,我不想要一个8.下一次,我可能会推出一个15.现在我想要再次滚动,但我不想要8或15.我现在处理这个问题的方法是使用do while循环,如果数字相同,我只需重新编辑。

这只是我家庭作业的一小部分,事实上,我已经努力满足所有要求,所以我想你可以说这是为了我个人的利益所以我可以写得恰到好处而不是最终“每日wtf“。

10 个答案:

答案 0 :(得分:18)

设置一个包含所有值的数组(如果你只做一些小数字,这只是一个有效的选项,比如你的例子中的25),如下所示:

var array = [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24];

然后,在0和数组长度之间选择一个随机数:

var num = Math.floor(Math.random() * array.length);

删除数组中的索引号:

var roll = array.splice(num, 1);

Javascript splice()从数组中删除索引项并将项作为数组返回。非常适合您的使用。

从滚动中抓取第一个索引,因为我们只切掉了1个:

var yourNumber = roll[ 0 ];

根据需要继续做多个卷。此外,您可能希望将原始数组存储为副本,以便您可以轻松地“重置”数字。

答案 1 :(得分:4)

这很容易。你不想要这个递归。这些答案非常糟糕。理想情况下,您也不想对数组进行硬编码。

<?xml version="1.0" encoding="utf-8"?>
<selector
  xmlns:android="http://schemas.android.com/apk/res/android"  android:shape="rectangle">

    <item>
        <shape>
            <solid android:color="#EC6118"/>
            <corners android:bottomRightRadius="0dp"
                 android:bottomLeftRadius="0dip"
                 android:topLeftRadius="10dip"
                 android:topRightRadius="0.1dp"/>
        </shape>
    </item>

</selector>

现在使用上面函数返回的值从你想要的任何数组中选择一个元素,就像这样:

function getRandomWithOneExclusion(lengthOfArray,indexToExclude){

  var rand = null;  //an integer

    while(rand === null || rand === indexToExclude){
       rand = Math.round(Math.random() * (lengthOfArray - 1));
    }

  return rand;
}

是的。如果你想排除超过值,那么你必须使它更复杂,但是为了排除一个值,这很有效。对此的递归解决方案是过度杀伤和糟糕的想法。

我还没有对此进行测试,但要排除多个元素,请尝试以下方法:

var arr = [];
var random = getRandomWithOneExclusion(arr.length,5);  //array has length x, we want to exclude the 5th element
var elem = arr[random];

上述方法与OP的原始方法听起来并没有太大区别。此方法正常工作,因为它不会以偏​​向方式从数组中进行采样。

答案 2 :(得分:2)

Hmz: - ?从阵列中随机获取项目并确保它们都是唯一的最快方法是:

var array = [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24];

Array.prototype.shuffle = function shuffle(){
    var tempSlot;
    var randomNumber;
    for(var i =0; i != this.length; i++){
        randomNumber = Math.floor(Math.random() * this.length);
        tempSlot = this[i]; 
        this[i] = this[randomNumber]; 
        this[randomNumber] = tempSlot;
    }
}

while(array.length!=0){
    array.shuffle();
    alert(array.pop());    
}

答案 3 :(得分:1)

这是没有递归且没有创建巨大数组的示例:

const getRandomWithExclude = (min, max, excludeArray) => {
  const randomNumber = Math.floor(Math.random() * (max - min + 1 - excludeArray.length)) + min;
  return randomNumber + excludeArray.sort((a, b) => a - b).reduce((acc, element) => { return randomNumber >= element - acc ? acc + 1 : acc}, 0);
}

const min = 1;
const max = 10;
const excludeArray = [8,2,5];
const result = getRandomWithExclude(min, max, excludeArray);

答案 4 :(得分:0)

我确信有几种方法可以做到这一点,但你可以将所有数字放入类似堆栈的内容中,将其全部混淆然后弹出以获取随机数。或者,每次随机搜索并将其从堆栈中删除。

答案 5 :(得分:0)

步骤1&gt;创建一个数组CHECK_ARRAY使用超出随机数范围的值填充数组[如果要在0-25内生成数字则填充26]

step2-&GT;生成一个随机数并将其添加到RANDOM_ARRAY并将其添加到CHECK_ARRAY

i=0;
CHECK_ARRAY[i]=random;
i++;

step3-&GT;生成一个新的随机数并通过CHECK_ARRAY,如果你发现26然后忽略,否则如果你发现重复然后重新生成一个随机数并再次继续第3步,直到找到一个唯一的随机数!

答案 6 :(得分:0)

这是经过测试的简单解决方案:

var array= [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24];
var random_value; 
var index;
var shuffled_array = new Array(24);

for (var i = 0; i < 24; i++) { 
random_value = array[Math.floor(Math.random()*array.length)]; //Returns a value between 1 and 24
index = array.indexOf(random_card); //Gets the index of the choosen random value
array.splice(index, 1); //Go to index of that array and remove it
shuffled_array [i] = random_value; //Put that value in a new array

window.alert("array: "+array+"\n"+"random_value: "+random_value+"\n"+"shuffled_array: "+shuffled_array);
}

在其他解决方案中,我认为他们忘记搜索索引。

答案 7 :(得分:0)

<div id="number" style="color: red; margin-left: 200px;">array</div>
<div id="arr" style="color: red; margin-left: 200px;">length</div>
<script>
  var arrayOfIndexesToExclude = new Array();
  function getRandomWithManyExclusions(){
    var rand = null;
      
		  	do{
		    	rand = Math.round(Math.random() * ( 9));
		    	if(arrayOfIndexesToExclude.length >= 10){
		 			  arrayOfIndexesToExclude.length = 0;	   			
		    	}
				}while(arrayOfIndexesToExclude.includes(rand));
			
			arrayOfIndexesToExclude.push(rand);  
    
    document.getElementById("number").innerHTML = arrayOfIndexesToExclude;
    document.getElementById("arr").innerHTML = arrayOfIndexesToExclude.length;
  }
</script>

答案 8 :(得分:0)

假设您需要从1...5范围内选择一个随机数,然后排除值2, 4

  • 1...3
  • 范围中选择一个随机数
  • 排除排除的号码列表
  • 对于小于随机数的每个排除数字:将1添加到随机数

function getRandomExcept(min, max, except) {
  except.sort(function(a, b) {
    return a - b;
  });
  var random = Math.floor(Math.random() * (max - min + 1 - except.length)) + min;
  var i;
  for (i = 0; i < except.length; i++) {
    if (except[i] > random) {
      break;
    }
    random++;
  }
  return random;
}

/*
 * Test iterations. Make sure that:
 * excluded numbers are skipped 
 * numbers are equally distributed
 */
(function(min, max, except) {
  var iterations = 1000000;
  var i;
  var random;
  var results = {};
  for (i = 0; i < iterations; i++) {
    random = getRandomExcept(min, max, except);
    results[random] = (results[random] || 0) + 1;
  }
  for (random in results) {
    console.log("value: " + random + ", count: " + results[random] + ", percent: " + results[random] * 100 / iterations + "%");
  }
})(1, 5, [2, 4]);

答案 9 :(得分:0)

只是发现自己处于一种需要为每个游戏坐标生成一个非常长的范围内的随机数的情况,但是要排除已经获取的一些坐标。

您可以想象,重新计算发生在帧之间(理想情况下在10-14ms之内),因此使用递归,while循环或生成极长的数组甚至都不是一种选择。

感谢Salman A和SebastianUmiński展示了解决问题的另一种更有效的方法。

所以这是我修改后的ES6功能,希望它对在我遇到问题的人中有所帮助:)

const getRandNum = (min, max, excluded = []) => {
  let num = Math.floor(Math.random() * (max - min + 1 - excluded.length) + min);
  excluded.sort((a, b) => a - b).every((exeption) => exeption <= num && (num++ || true));
  return num;
};

console.log(getRandNum(0, 24, [8]));