随机数,不等于前一个数字

NJV*_*NJV 26 javascript

我需要得到随机数,但它不应该等于之前的数字.这是我的代码片段.但它不起作用.

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());
Run Code Online (Sandbox Code Playgroud)

Nin*_*olz 20

这个答案提出了三次尝试

  1. 一个简单的版本与功能的属性getNumber,last,其中存储最后随机值.

  2. 如果小于,则使用对minmax值的闭包的版本,引发异常.maxmin

  3. 一个版本,结合了闭包和保持所有随机值的想法,并在合适的时候使用它.


您可以使用属性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());
}
Run Code Online (Sandbox Code Playgroud)
.as-console-wrapper { max-height: 100% !important; top: 0; }
Run Code Online (Sandbox Code Playgroud)


关于间隔和最后一个随机值的闭包的另一个提议.

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
Run Code Online (Sandbox Code Playgroud)
.as-console-wrapper { max-height: 100% !important; top: 0; }
Run Code Online (Sandbox Code Playgroud)


该提议使用该想法来最小化新随机数的调用.它适用于两个变量,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());
}
Run Code Online (Sandbox Code Playgroud)
.as-console-wrapper { max-height: 100% !important; top: 0; }
Run Code Online (Sandbox Code Playgroud)

  • 我只调用`getNumber`,`getNumber.last`的属性,而不再是函数. (3认同)

Con*_*Fan 15

以下方法在[min,max]范围内生成一个新的随机数,并确保此数字与前一个不同,没有循环且没有递归调用(Math.random()仅调用一次):

  • 如果存在先前的数字,请将最大值减1
  • 在该范围内生成一个新的随机数
  • 如果新数字等于或大于前一个数字,则添加一个
    (替代方法:如果新数字等于前一个数字,则将其设置为最大值+ 1)

为了将先前的数字保留在闭包中,getNumber可以在IIFE中创建:

// 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());
}
Run Code Online (Sandbox Code Playgroud)
.as-console-wrapper {
  max-height: 100% !important;
  top: 0;
}
Run Code Online (Sandbox Code Playgroud)

通过在以下语句中添加1来使[min,max]范围包含在内max - min:

var value = Math.floor(Math.random() * (max - min + 1)) + min;
Run Code Online (Sandbox Code Playgroud)

这不是问题的要求,但使用包容性范围对我来说更自然.


Eti*_*tin 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
Run Code Online (Sandbox Code Playgroud)

实例:https://jsfiddle.net/menv0tur/3/


Mac*_*ora 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);
}
Run Code Online (Sandbox Code Playgroud)

正如您在测试中看到的那样,我们永远不会有两个相同的值彼此相邻.我还添加了一些console.log来显示需要运行多少次递归才能找到与前一个不同的下一个数字.


Tom*_*aas 5

通用解决方案

跟踪最后生成的数字。生成新号码时,请检查它是否与上一个不同。如果不是,请继续生成新的数字,直到它不同为止,然后输出它。

工作演示

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);
Run Code Online (Sandbox Code Playgroud)

关于计算效率的评论

如评论和其他答案中所述,上述方法的潜在缺点是,如果生成的数字等于前一个数字,则可能需要进行几次尝试以生成随机数。请注意,需要进行多次尝试的可能性非常低(遵循快速下降的几何分布)。出于实际目的,这不太可能产生明显的影响。

但是,可以通过从范围[min,max]中的数字集中直接绘制一个随机数来排除新的随机数,而先前尝试绘制的数字除外:这在@答案中得到了很好的证明ConnorsFan,每个函数调用仅生成一个随机数,而随机性仍然保留。

  • @ guest271314,我没有达到要求。在这种情况下,ConnorsFan似乎做对了。 (2认同)

tew*_*hia 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;
};
Run Code Online (Sandbox Code Playgroud)