我需要获得随机数,但它不应该等于之前的数字。这是我的代码片段。但它不起作用。
function getNumber(){
var min = 0;
var max = 4;
var i;
i = Math.floor(Math.random() * (max - min)) + min;
if (i=== i) {
i = Math.floor(Math.random() * (max - min)) + min;
}
return i;
};
console.log(getNumber());
答案 0 :(得分:19)
这个答案提出了三次尝试
一个简单版本,其属性为getNumber
,last
,用于存储最后一个随机值。
如果min
小于max
,则对max
和min
值使用闭包的版本会引发异常。
一个版本,它结合了闭包和保留所有随机值的想法,并在合适的时候使用它。
<强>一强>
您可以使用getNumber
的属性来存储最后一个号码并使用do ... while
循环。
function getNumber() {
var min = 0,
max = 4,
random;
do {
random = Math.floor(Math.random() * (max - min)) + min;
} while (random === getNumber.last);
getNumber.last = random;
return random;
};
var i;
for (i = 0; i < 100; i++) {
console.log(getNumber());
}
.as-console-wrapper { max-height: 100% !important; top: 0; }
<强>两个强>
关于间隔和最后一个随机值的闭包的另一个建议。
function setRandomInterval(min, max) {
var last;
if (min >= max) {
throw 'Selected interval [' + min + ', ' + max + ') does not work for random numbers.';
}
return function () {
var random;
do {
random = Math.floor(Math.random() * (max - min)) + min;
} while (random === last);
last = random;
return random;
};
}
var i,
getRandom = setRandomInterval(0, 4);
for (i = 0; i < 100; i++) {
console.log(getRandom());
}
setRandomInterval(4, 4); // throw error
.as-console-wrapper { max-height: 100% !important; top: 0; }
<强>三强>
此提案使用该想法来最小化新随机数的调用。它适用于两个变量value
用于连续相同的随机值,count
用于保存相同值的计数。
如果给出了保存的计数,并且该值与最后一个值不相等,则该函数首先查找。如果发生这种情况,则返回保存的值并减少计数。
否则,如上所述生成并检查新的随机数(第一个提议)。如果该数字等于最后一个值,则计数递增,并继续生成新的随机值。
结果,几乎所有先前生成的随机值都被使用。
function setRandomInterval(min, max) {
var last, // keeping the last random value
value, // value which is repeated selected
count = 0, // count of repeated value
getR = function () { return Math.floor(Math.random() * (max - min)) + min; };
if (min >= max) {
throw 'Selected interval [' + min + ', ' + max + ') does not work for random numbers.';
}
return function () {
var random;
if (count && value !== last) {
--count;
return last = value;
}
random = getR();
while (random === last) {
value = random;
++count;
random = getR();
}
return last = random;
};
}
var i,
getRandom = setRandomInterval(0, 4);
for (i = 0; i < 100; i++) {
console.log(getRandom());
}
.as-console-wrapper { max-height: 100% !important; top: 0; }
答案 1 :(得分:15)
以下方法在[min,max]范围内生成一个新的随机数,并确保此数字与前一个不同,没有循环且没有递归调用(Math.random()
只调用一次):< / p>
为了将先前的数字保留在闭包中,可以在IIFE中创建getNumber
:
// getNumber generates a different random number in the inclusive range [0, 4]
var getNumber = (function() {
var previous = NaN;
return function() {
var min = 0;
var max = 4 + (!isNaN(previous) ? -1 : 0);
var value = Math.floor(Math.random() * (max - min + 1)) + min;
if (value >= previous) {
value += 1;
}
previous = value;
return value;
};
})();
// Test: generate 100 numbers
for (var i = 0; i < 100; i++) {
console.log(getNumber());
}
&#13;
.as-console-wrapper {
max-height: 100% !important;
top: 0;
}
&#13;
通过在以下语句中向max - min
添加1,[最小,最大]范围为inclusive:
var value = Math.floor(Math.random() * (max - min + 1)) + min;
这不是问题的要求,但使用包容性范围对我来说更自然。
答案 2 :(得分:9)
此主题中的大部分答案都过于复杂。
以下是我将如何做到这一点的简明例子:
function getNumber(){
return (getNumber.number = Math.floor(Math.random() * (4 + 1))) === getNumber.lastNumber ? getNumber() : getNumber.lastNumber = getNumber.number;
}
console.log(getNumber()); // Generates a random number between 0 and 4
答案 3 :(得分:5)
首先,函数应该与之前的值进行比较,现在我们只有i
变量与自身进行比较。为了确保我们没有先前的值,我们需要在内部循环(在我的解决方案中递归),因为单if statement
不能确保第二个随机数不相同(存在机会)。您的数字设置非常小,因此碰撞的可能性很高,循环可能很少执行。
function getNumber(prev){
var min = 0;
var max = 4;
var next;
next = Math.floor(Math.random() * (max - min)) + min;
if (next===prev) {
console.log("--run recursion. Our next is ="+next); //log only for test case
next = getNumber(prev); //recursive
}
return next;
};
//test 100 times
var num=0;
for ( var i=0; i<100; i++){
num=getNumber(num);
console.log(num);
}
正如您在测试中看到的那样,我们永远不会有两个相同的值彼此相邻。我还添加了一些console.log
来显示递归需要运行多少次才能找到与前一个不同的下一个数字。
答案 4 :(得分:4)
您需要一个范围大于getNumber
函数本地变量的变量。尝试:
var j;
function getNumber(){
var min = 0;
var max = 4;
var i = Math.floor(Math.random() * (max - min)) + min;
if (j === i) {
i = getNumber();
}
j = i;
return i;
};
答案 5 :(得分:4)
从一开始就从可能值集中删除先前的值。
function getNumber(previous) {
var numbers = [0, 1, 2, 3, 4];
if (previous !== undefined) {
numbers.splice(numbers.indexOf(previous), 1);
}
var min = 0;
var max = numbers.length;
var i;
i = Math.floor(Math.random() * (max - min)) + min;
return numbers[i];
};
//demonstration. No 2 in a row the same
var random;
for (var i = 0; i < 100; i++) {
random = getNumber(random);
console.log(random);
}
答案 6 :(得分:4)
跟踪上次生成的号码。生成新号码时,请检查它是否与上一个号码不同。如果没有,继续生成新数字直到它不同,然后输出它。
var getNumber = (function(){
var min = 0;
var max = 4;
var last = -1;
return function(){
var current;
do{
// draw a random number from the range [min, max]
current = Math.floor(Math.random() * (max + 1 - min)) + min;
} while(current === last)
return (last = current);
}
})();
// generate a sequence of 100 numbers,
// see that they all differ from the last
for(var test = [], i = 0; i < 100; i++){
test[i] = getNumber();
}
console.log(test);
正如评论和其他答案中所讨论的,上述方法的一个潜在缺点是,如果生成的数字等于前一个,则可能需要多次尝试生成随机数。请注意,需要多次尝试的概率非常低(它遵循快速下降的geometric distribution)。出于实际目的,这不太可能产生任何明显的影响。
但是,可以避免多次尝试生成新的随机数,方法是从[min,max]范围内的数字组中直接绘制一个随机数,不包括先前绘制的数字:这在通过@ConnorsFan回答,其中每个函数调用只生成一个随机数,而随机性仍然保留。
答案 7 :(得分:3)
您可以使用@NinaScholz模式的实现,其中前一个值存储为调用函数的属性,用条件逻辑代替递增或递减循环的当前返回值。
如果当前值等于先前返回的值,则在返回更改的值之前,在当前函数调用期间更改当前值,而不使用循环或递归。
var t = 0;
function getNumber() {
var min = 0,
max = 4,
i = Math.floor(Math.random() * (max - min)) + min;
console.log(`getNumber calls: ${++t}, i: ${i}, this.j: ${this.j}`);
if (isNaN(this.j) || this.j != i) {
this.j = i;
return this.j
} else {
if (this.j === i) {
if (i - 1 < min || i + 1 < max) {
this.j = i + 1;
return this.j
}
if (i + 1 >= max || i - 1 === min) {
this.j = i - 1;
return this.j
}
this.j = Math.random() < Math.random() ? --i : ++i;
return this.j
}
}
};
for (var len = 0; len < 100; len++) {
console.log("random number: ", getNumber());
}
答案 8 :(得分:2)
此解决方案使用ES6生成器并避免生成随机数,直到找到符合前提条件的数字(两个相关数字必须不同)。
主要思想是拥有一个包含数字的数组和一个包含索引的数组。然后,您获得一个随机索引(为了符合前提条件,索引的数组将是使用先前选择的索引过滤索引数组的结果)。返回值将是与数字'数组中的索引对应的数字。
function* genNumber(max = 4) {// Assuming non-repeating values from 0 to max
let values = [...Array(max).keys()],
indexes = [...Array(max).keys()],
lastIndex,
validIndexes;
do {
validIndexes = indexes.filter((x) => x !== lastIndex);
lastIndex = validIndexes[Math.floor(Math.random() * validIndexes.length)];
yield values[lastIndex];
} while(true);
}
var gen = genNumber();
for(var i = 0; i < 100; i++) {
console.log(gen.next().value);
}
如果你想检查结果,这是fiddle。
答案 9 :(得分:2)
将先前生成的随机数保存在数组中,使用现有数字检查新数字,可以防止重复随机数生成。
// global variables
tot_num = 10; // How many number want to generate?
minimum = 0; // Lower limit
maximum = 4; // upper limit
gen_rand_numbers = []; // Store generated random number to prevent duplicate.
/*********** **This Function check duplicate number** ****************/
function in_array(array, el) {
for (var i = 0; i < array.length; i++) {
if (array[i] == el) {
return true;
}
}
return false;
}
/*--- This Function generate Random Number ---*/
function getNumber(minimum, maximum) {
var rand = Math.floor(Math.random() * (maximum - minimum + 1)) + minimum;
if (gen_rand_numbers.length <= (maximum - minimum)) {
if (!in_array(gen_rand_numbers, rand)) {
gen_rand_numbers.push(rand);
//alert(rand)
console.log(rand);
return rand;
} else {
return getNumber(minimum, maximum);
}
} else {
alert('Final Random Number: ' + gen_rand_numbers);
}
}
/*--- This Function call random number generator to get more than one random number ---*/
function how_many(tot_num) {
for (var j = 0; j < tot_num; j++) {
getNumber(minimum, maximum);
}
}
<script src = "https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js" > </script>
<input type = "button" onclick = "how_many(4)" value = "Random Number" >
答案 10 :(得分:1)
您可以使用linear congruential generator的增强实现。
线性同余生成器(LCG)是一种算法,它产生一系列伪随机数,并用不连续的分段线性方程计算。
以下函数返回一个带种子的随机数以及最小值和最大值:
Math.seededRandom = function(seed, min, max) {
max = max || 1;
min = min || 0;
// remove this for normal seeded randomization
seed *= Math.random() * max;
seed = (seed * 9301 + 49297) % 233280;
let rnd = seed / 233280.0;
return min + rnd * (max - min);
};
在您的情况下,因为您从不希望新号码与之前的号码相同,所以您可以将之前生成的号码作为种子传递。
以下是生成100个随机数的示例:
Math.seededRandom = function(seed, min, max) {
max = max || 1;
min = min || 0;
// remove this for normal seeded randomization
seed *= Math.random() * max;
seed = (seed * 9301 + 49297) % 233280;
let rnd = seed / 233280.0;
return min + rnd * (max - min);
};
let count = 0;
let randomNumbers = [];
let max = 10;
do {
let seed = (randomNumbers[randomNumbers.length -1] || Math.random() * max);
randomNumbers.push(Math.seededRandom(seed, 0, max));
count++;
} while (count < 100)
console.log(randomNumbers);
&#13;
答案 11 :(得分:1)
一个有趣的答案,在一行中生成0到4的数字:
console.log(Math.random().toString(5).substring(2).replace(/(.)\1+/g, '$1').split('').map(Number));
&#13;
说明:
Math.random() //generate a random number
.toString(5) //change the number to string, use only 5 characters for it (0, 1, 2, 3, 4)
.substring(2) //get rid of '0.'
.replace(/(.)\1+/g, '$1') //remove duplicates
.split('') //change string to array
.map(Number) //cast chars into numbers
使用生成器的更长版本:
let Gen = function* () {
const generateString = (str) => str.concat(Math.random().toString(5).substring(2)).replace(/(.)\1+/g, '$1');
let str = generateString('');
let set = str.split('').map(Number);
while (true) {
if (set.length === 0) {
str = generateString(str).substring(str.length);
set = str.split('').map(Number);
}
yield set.pop();
}
}
let gen = Gen();
console.log(gen.next().value);
console.log(gen.next().value);
console.log(gen.next().value);
console.log(gen.next().value);
console.log(gen.next().value);
console.log(gen.next().value);
console.log(gen.next().value);
console.log(gen.next().value);
console.log(gen.next().value);
console.log(gen.next().value);
console.log(gen.next().value);
&#13;
答案 12 :(得分:1)
function getNumber(){
var min = 0;
var max = 4;
var i;
i = Math.floor(Math.random() * (max - min)) + min;
while(i==getNumber.last)
i = Math.floor(Math.random() * (max - min)) + min;
getNumber.last=i;
return i;
};
console.log(getNumber());
答案 13 :(得分:0)
试试这个
var prev_no = -10;
function getNumber(){
var min = 0;
var max = 4;
var i;
i = Math.floor(Math.random() * (max - min)) + min;
while (i == prev_no) {
i = Math.floor(Math.random() * (max - min)) + min;
prev_no = i;
}
return i;
};
console.log(getNumber());
答案 14 :(得分:0)
您可以使用Promise
,Array.prototype.forEach()
,setTimeout
。创建并迭代.length
设置为max
的数组;在setTimeout
回调中使用.forEach()
并将duration
设置为随机值,以将数组的索引推送到新数组,以便在新数组中非均匀分布索引。已从Promise
函数返回已解决的getNumber
Promise
.then()
值为.length
的{{1}} max
数组,其中index
来自.forEach()
function getNumber(max) {
this.max = max;
this.keys = [];
this.arr = Array.from(Array(this.max));
this.resolver = function getRandom(resolve) {
this.arr.forEach(function each(_, index) {
setTimeout(function timeout(g) {
g.keys.push(index);
if (g.keys.length === g.max) {
resolve(g.keys)
};
}, Math.random() * Math.PI * 100, this);
}, this)
};
this.promise = new Promise(this.resolver.bind(this));
}
var pre = document.querySelector("pre");
var random1 = new getNumber(4);
random1.promise.then(function(keys) {
pre.textContent += keys.length + ":\n";
keys.forEach(function(key) {
pre.textContent += key + " ";
})
});
var random2 = new getNumber(1000);
random2.promise.then(function(keys) {
pre.textContent += "\n\n";
pre.textContent += keys.length + ":\n";
keys.forEach(function(key) {
pre.textContent += key + " ";
})
});
回调为没有重复条目的值。
pre {
white-space: pre-wrap;
width: 75vw;
}
&#13;
<pre></pre>
&#13;
timer
&#13;
答案 15 :(得分:-1)
除非您进行数据库查询以检查是否存在新号码,否则无法实现此目的。如果存在,请重复此过程。
有一种架构可能性,使得唯一的随机数是生成两个随机数并组合字符串。
例如:
rand_num1 = rand(5);
rand_num2 = rand(4);
然后组合rand_num1和rand_num2,它更像是唯一的
实际例子:
(23456)(2345)
(23458)(1290)
(12345)(2345)
同时增加位数以减少重复。