生成0到‘x’之间唯一随机数(整数)

58

我需要生成一组独一无二且在0和给定数字之间的整数。

也就是说:

var limit = 10;
var amount = 3;

我该如何使用 JavaScript 生成三个介于 1 和 10 之间的唯一数字?


1
дҪ жҳҜжҢҮиҢғеӣҙеңЁ1вүӨxвүӨ10зҡ„3дёӘж•ҙж•°пјҢиҝҳжҳҜиҢғеӣҙеңЁ1вүӨx<10зҡ„дёүдёӘжө®зӮ№ж•°пјҹ - Jeremy
4
“重复问题”不是正确的问题。这个问题包含一个“额外”的要求:随机数应该是“唯一”的。 - Rob W
这个回答解决了你的问题吗?在JavaScript中生成特定范围内的随机整数? - Michael Freidgeim
16个回答

77
使用基本的 Math 方法:
  • Math.random() 返回介于 0 和 1(包括 0,不包括 1)之间的随机数。
  • 将此数字乘以所需的最大数字(例如 10)
  • 向下舍入此数字到其最近的整数

Math.floor(Math.random()*10) + 1

示例:

//Example, including customisable intervals [lower_bound, upper_bound)
var limit = 10,
    amount = 3,
    lower_bound = 1,
    upper_bound = 10,
    unique_random_numbers = [];

if (amount > limit) limit = amount; //Infinite loop if you want more unique
                                    //Natural numbers than exist in a
                                    // given range
while (unique_random_numbers.length < limit) {
    var random_number = Math.floor(Math.random()*(upper_bound - lower_bound) + lower_bound);
    if (unique_random_numbers.indexOf(random_number) == -1) { 
        // Yay! new random number
        unique_random_numbers.push( random_number );
    }
}
// unique_random_numbers is an array containing 3 unique numbers in the given range

@benhowdle89 在循环中,变量random_numbers。我先放逻辑,然后是示例。 - Rob W
@benhowdle89 有人将你的问题标记为作业。这是真的吗?如果不是,请移除该标记。 - Rob W
1
不,它不是重复的。 - benhowdle89
18
答案不正确。不要使用round() - 使用floor()或ceil(),因为否则,您的结果将不会均匀分布。例如,如果您想要一个介于0和3之间的随机整数,并使用round(),那么最终您将更经常地得到1和2,而不是0和3,因为有更多可能的随机值会四舍五入为1和2,因为round()可以向上或向下舍入。使用floor或ceil强制浮点数始终朝着同一方向舍入,从而创建更加分布均匀的结果。 - Eric Rowell
不要使用Math.round。使用Math.floor,否则您将发现自己的上限等于1+top。Math.floor(Math.random()*10) + 1http://www.w3schools.com/jsref/jsref_random.asp - phillihp
显示剩余3条评论

22
Math.floor(Math.random() * (limit+1))

Math.random() 生成一个介于 0 和 1 之间的浮点数,Math.floor() 将其向下取整为整数。

通过将其乘以一个数字,您可以有效地使范围变为 0..number-1。如果您希望在 num1num2 的范围内生成它,请执行以下操作:

Math.floor(Math.random() * (num2-num1 + 1) + num1)

为了生成更多的数字,只需使用一个for循环,并将结果放入数组中或直接写入文档。


如果我想要一个在0到5之间的随机数,但是这个代码没有生成任何结果等于0。我认为这是因为+1使得最小结果等于1。 - paulzag
@paulzag 你说得对,感谢指出!一个简单的解决方法是将 +1 移到 Math.floor 内部,但这样做可能会很少生成超过上限的数字... 嗯 - Llamageddon
我尝试了num1 = 0和num2 = 10,如果我运行足够多次,它会生成0和10。非常好的答案 - 谢谢! - Daniel
@Daniel 是的,但问题是它很少会超过限制1,而且除了从limit+1中减去最小的浮点单位之外,没有其他修复方法,而我完全不知道如何做到这一点。 - Llamageddon

5
function generateRange(pCount, pMin, pMax) {
    min = pMin < pMax ? pMin : pMax;
    max = pMax > pMin ? pMax : pMin;
    var resultArr = [], randNumber;
    while ( pCount > 0) {
        randNumber = Math.round(min + Math.random() * (max - min));
        if (resultArr.indexOf(randNumber) == -1) {
            resultArr.push(randNumber);
            pCount--;
        }
    }
    return resultArr;
}

根据所需的范围,返回整数的方法可以更改为:ceil(a,b]、round [a,b]、floor [a,b),对于(a,b)的情况,则需要将min加1并使用floor。

1
请注意,这不是均匀分布的。我在尝试生成一个[0,100]范围内的(非唯一)随机数时尝试了您的Math.round(min + Math.random() * (max - min))解决方案,并在生成了一百万个数字的测试中发现,相比于其他结果,我得到了大约一半的0100实例。 - PrincessRTFM

3
Math.floor(Math.random()*limit)+1

2
这里是另一种确保数字唯一的算法:
  1. 生成从0到x的所有数字的数组
  2. 将数组随机排序
  3. 选择前n个元素
与生成随机数直到得到唯一数字的方法相比,这种方法使用更多内存,但运行时间更稳定 - 结果保证在有限时间内找到。如果上限相对较低或要取的数量相对较高,则此方法效果更好。
我的答案为了简单起见使用了Lodash库,但您也可以不使用该库实现上述算法。
// assuming _ is the Lodash library

// generates `amount` numbers from 0 to `upperLimit` inclusive
function uniqueRandomInts(upperLimit, amount) {
    var possibleNumbers = _.range(upperLimit + 1);
    var shuffled = _.shuffle(possibleNumbers);
    return shuffled.slice(0, amount);
}

是的!有一个有限运行时间的解决方案! - KFunk

2
for(i = 0;i <amount; i++)
{
    var randomnumber=Math.floor(Math.random()*limit)+1
    document.write(randomnumber)
}

你永远不会得到0,我认为这是不正确的。 - NaturalBornCamper
@NaturalBornCamper 这个问题指定了一个介于1和10之间的数字。 - Neeta

1
这些答案要么不提供唯一值,要么太长了(其中一个甚至添加了外部库来完成这样一个简单的任务)。
1. 生成一个随机数。 2. 如果我们已经有了这个随机数则返回到步骤1,否则保留它。 3. 如果我们还没有得到想要的随机数数量,则返回到步骤1。

function uniqueRandoms(qty, min, max){
  var rnd, arr=[];
  do { do { rnd=Math.floor(Math.random()*max)+min }
      while(arr.includes(rnd))
      arr.push(rnd);
  } while(arr.length<qty)
  return arr;
}

//generate 5 unique numbers between 1 and 10
console.log( uniqueRandoms(5, 1, 10) );

...以及相同功能的压缩版本:

function uniqueRandoms(qty, min, max) { var a = []; do { do { r = Math.floor(Math.random() * max) + min } while (a.includes(r)); a.push(r) } while (a.length < qty); return a }


是的,但是尝试使用 uniqueRandoms(10, 2, 5) 会导致无限循环。 - Jeremy Iglehart

1

类似这样的东西

var limit = 10;
var amount = 3;
var nums = new Array();

for(int i = 0; i < amount; i++)
{
    var add = true;
    var n = Math.round(Math.random()*limit + 1;
    for(int j = 0; j < limit.length; j++)
    {
        if(nums[j] == n)
        {
            add = false;
        }
    }
    if(add)
    {
        nums.push(n)
    }
    else
    {
        i--;
    }
}

1
var randomNums = function(amount, limit) {
var result = [],
    memo = {};

while(result.length < amount) {
    var num = Math.floor((Math.random() * limit) + 1);
    if(!memo[num]) { memo[num] = num; result.push(num); };
}
return result; }

这似乎可行,并且不断查找重复项。

1
为了避免无限循环,您应该将while循环中的条件更改为类似于while(result.length < amount && result.length <= max - 1)的内容。 - ViRPo

0

随机数组,切片

类似于@rory-okane答案,但不使用lodash。

  • 时间复杂度和空间复杂度均为O(n),其中n=limit

  • 具有一致的运行时间

  • 支持正数或负数范围

  • 理论上,它应该支持从0±2^32 - 1的范围

    这个限制是由于Javascript数组只支持2^32 - 1索引,根据ECMAScript规范

    我在10^8处停止测试,因为我的浏览器在这里变得奇怪,只能处理负数到-10^7,我得到了一个Uncaught RangeError: Invalid array length错误(耸肩)

  • 额外功能:如果您只传递一个参数,则生成长度为n、范围为0limit的随机数组

let uniqueRandomNumbers = (limit, amount = limit) => {
    let array = Array(Math.abs(limit));
    for (let i = 0; i < array.length; i++) array[i] = i * Math.sign(limit);
    let currentIndex = array.length;
    let randomIndex;
    while(currentIndex > 0) {
        randomIndex = Math.floor(Math.random() * currentIndex--);
        [array[currentIndex], array[randomIndex]] = [array[randomIndex], array[currentIndex]];
    }
    return array.slice(0, Math.abs(amount));
}

console.log(uniqueRandomNumbers(10, 3));
console.log(uniqueRandomNumbers(-10, 3));

//bonus feature:
console.log(uniqueRandomNumbers(10));

致谢:

我个人之所以来到这里,是因为我想生成长度为n的随机数组。以下是其他SO问题,它们帮助我找到了自己的用例答案。感谢大家的贡献,你们让我的生活变得更美好。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接