在JavaScript中生成非重复随机数

时间:2019-05-04 20:54:08

标签: javascript arrays random numbers

如何确保不会重复输入随机数?现在,这不起作用。我正在使用本地数组存储以前的结果。

getUniqueRandomNumber(x){
     var index;
     var viewedIndices = [];
     index = Math.floor(Math.random() * (x));
     if(viewedIndices.includes(index)) 
     {
       viewedIndices.push(index);
       this.getUniqueRandomNumber(x);
     }
     else { 
       console.log(index);
       return index;
    }
 }

4 个答案:

答案 0 :(得分:3)

您需要使viewedIndicies 持久,以便进一步调用getUniqueRandomNumber可以看到先前添加的元素。与其跟踪标记,不如跟踪所选的简单数字 可能会更容易。您可以使用Set而不是数组来降低计算复杂度(.hasO(1).includesO(N))。

const makeGetUniqueRandomNumber = (x) => {
  const chosenNumbers = new Set();
  return () => {
    if (chosenNumbers.size === x) {
      throw new Error('No more uniques!');
    }
    let num;
    do {
      num = Math.floor(Math.random() * x);
    } while (chosenNumbers.has(num));
    chosenNumbers.add(num);
    return num;
  };
};

const getRand5 = makeGetUniqueRandomNumber(5);
console.log(
  getRand5(),
  getRand5(),
  getRand5(),
  getRand5(),
  getRand5()
);
try {
  getRand5();
} catch(e) {
  console.log(e.message);
}

const anotherGetRand5 = makeGetUniqueRandomNumber(5);
console.log(
  anotherGetRand5(),
  anotherGetRand5(),
  anotherGetRand5(),
  anotherGetRand5(),
  anotherGetRand5()
);

您还可以提前生成整个随机数数组,然后每次选择另一个splice,但是当可能性很大但只需要几个随机数时,效率会很低数字。正确的选择取决于一个会话中所需唯一编号与随机范围大小的比例。

如果在不了解ES6(ES2015)语法的古老环境中进行开发,则可以使用数组而不是Set,并通过Babel传递代码:

"use strict";

var makeGetUniqueRandomNumber = function makeGetUniqueRandomNumber(x) {
  var chosenNumbers = [];
  return function () {
    if (chosenNumbers.length === x) {
      throw new Error('No more uniques!');
    }

    var num;

    do {
      num = Math.floor(Math.random() * x);
    } while (chosenNumbers.includes(num));

    chosenNumbers.push(num);
    return num;
  };
};

var getRand5 = makeGetUniqueRandomNumber(5);
console.log(getRand5(), getRand5(), getRand5(), getRand5(), getRand5());

try {
  getRand5();
} catch (e) {
  console.log(e.message);
}

var anotherGetRand5 = makeGetUniqueRandomNumber(5);
console.log(anotherGetRand5(), anotherGetRand5(), anotherGetRand5(), anotherGetRand5(), anotherGetRand5());

答案 1 :(得分:2)

您有两个错误,oné是每次尝试都会清除的函数内部的数组,然后有错误的逻辑以无限循环结尾。

const usedIndexes = [];    
function getUniqueRandomNumber(x) {
  const index = Math.floor(Math.random() * (x));
  if (usedIndexes.includes(index)) {
    return this.getUniqueRandomNumber(x);
  } else { 
    console.log(index);
    usedIndexes.push(index);
    return index;
  }
}

此外,我会考虑在这种情况下使用Set而不是数组。

const usedIndexes = new Set();    
function getUniqueRandomNumber(max, min = 0) {
  const newNumber = Math.floor(Math.random() * (max - min) + min);
  if (usedIndexes.has(newNumber)) {
    return this.getUniqueRandomNumber(max, min);
  } else { 
    usedIndexes.add(newNumber);
    return newNumber;
  }
}

我还编辑了变量名以更好地反映它们的实际用法,并为随机数添加了最小值。

答案 2 :(得分:0)

这不起作用,因为每次调用 getUniqueRandomNumber 时,它将 viewedIndices 数组重新初始化为空数组。因此,为了使您的代码正常工作,请在函数调用上方声明此数组。

答案 3 :(得分:0)

您是只希望编写的代码正常工作还是想要更好的解决方案?选择随机数直到不重复为止,这是灾难的根源,因为程序会停顿几秒钟,试图找到一个尚未使用的数字。当然,如果您只要求提供几个数字,也许并不需要花很多时间,但是代码位于您的代码库中,并且从现在起5年后,其他人正在使用它,而他们不知道代码中存在定时炸弹。想象一下,数组中有10000个元素,并且已选择9999个元素。可能需要一百万次重试才能最终选择一个未使用的索引。

该代码似乎正在选择变量名称为indexviewedIndices的索引

一种选择随机元素的方法是只是从数组中随机删除然后删除。如果需要复制数组

const array = ["a", "b", "c", "d", "e", "f", "g"];

while (array.length) {
  const ndx = Math.random() * array.length | 0;
  const elem = array.splice(ndx, 1)[0];
  console.log(elem);
}

注意:使用Math.random() * value | 0获得随机数0->正整数比Math.floor(Math.random() * value)快,因为|是运算符,而不是附加到Math对象的函数必须在每次通话时检查该电话,以查看是否已被替换。