在JavaScript开发中,生成唯一随机数并提取最小值是比较常见的需求,比如我们需要生成10个不重复的1到100之间的随机数,然后找到其中最小的那个数,下面介绍几种高效的实现方式。

方法一:利用Set特性生成唯一随机数
Set是ES6引入的数据结构,它内部存储的成员都是唯一的,重复的值会被自动过滤,非常适合用来生成唯一随机数。我们可以先通过循环生成随机数,将随机数添加到Set中,直到Set的长度达到我们需要的数量,再从Set中提取最小值。
// 生成指定范围、指定数量的唯一随机数,并提取最小值
function getUniqueRandomAndMin(start, end, count) {
// 边界校验
if (count > (end - start + 1)) {
throw new Error('生成数量超过范围可生成的不重复随机数最大值');
}
const randomSet = new Set();
// 循环生成随机数,直到Set长度达到目标数量
while (randomSet.size < count) {
const randomNum = Math.floor(Math.random() * (end - start + 1)) + start;
randomSet.add(randomNum);
}
// 将Set转为数组,使用Math.min提取最小值
const randomArr = Array.from(randomSet);
const minVal = Math.min(...randomArr);
return {
uniqueRandomList: randomArr,
minValue: minVal
};
}
// 示例:生成1到100之间的10个唯一随机数,并提取最小值
const result = getUniqueRandomAndMin(1, 100, 10);
console.log('唯一随机数列表:', result.uniqueRandomList);
console.log('最小值:', result.minValue);
方法二:先打乱有序数组再截取
如果我们需要生成的唯一随机数覆盖整个指定范围,或者范围不大,也可以先生成一个包含范围内所有有序数字的数组,然后通过洗牌算法打乱数组顺序,再截取前N个作为唯一随机数,最后提取最小值。这种方式在数据量不大时,避免了循环判断重复的性能消耗。
// 洗牌算法实现数组打乱
function shuffleArray(arr) {
const newArr = [...arr];
for (let i = newArr.length - 1; i > 0; i--) {
const randomIndex = Math.floor(Math.random() * (i + 1));
[newArr[i], newArr[randomIndex]] = [newArr[randomIndex], newArr[i]];
}
return newArr;
}
// 生成唯一随机数并提取最小值
function getUniqueRandomAndMinByShuffle(start, end, count) {
if (count > (end - start + 1)) {
throw new Error('生成数量超过范围可生成的不重复随机数最大值');
}
// 生成范围内所有有序数组
const allNums = [];
for (let i = start; i <= end; i++) {
allNums.push(i);
}
// 打乱数组并截取前count个
const shuffledArr = shuffleArray(allNums);
const uniqueRandomList = shuffledArr.slice(0, count);
// 提取最小值
const minValue = Math.min(...uniqueRandomList);
return {
uniqueRandomList,
minValue
};
}
// 示例:生成1到50之间的5个唯一随机数,并提取最小值
const result2 = getUniqueRandomAndMinByShuffle(1, 50, 5);
console.log('唯一随机数列表:', result2.uniqueRandomList);
console.log('最小值:', result2.minValue);
两种方法的对比
我们可以通过下面的表格对比两种方法的适用场景:
| 方法 | 优势 | 劣势 | 适用场景 |
|---|---|---|---|
| Set循环生成法 | 不需要提前生成全量范围数组,内存占用小 | 当生成数量接近范围最大值时,循环重复概率高,性能下降 | 生成数量远小于范围最大值,比如1到100000生成10个唯一随机数 |
| 洗牌截取生成法 | 生成速度稳定,不会出现循环重复判断的消耗 | 需要提前生成全量范围数组,范围很大时内存占用高 | 范围较小,或者生成数量接近范围最大值,比如1到100生成90个唯一随机数 |
提取最小值的其他实现方式
除了使用Math.min配合扩展运算符的方式,我们也可以通过循环遍历数组来提取最小值,这种方式在数组长度非常大时,比扩展运算符更节省内存,避免栈溢出问题。
// 循环遍历提取最小值
function getMinValue(arr) {
if (arr.length === 0) {
return null;
}
let min = arr[0];
for (let i = 1; i < arr.length; i++) {
if (arr[i] < min) {
min = arr[i];
}
}
return min;
}
// 配合Set生成法的示例
const randomSet = new Set();
while (randomSet.size < 8) {
randomSet.add(Math.floor(Math.random() * 50) + 1);
}
const randomArr = Array.from(randomSet);
const minVal = getMinValue(randomArr);
console.log('唯一随机数列表:', randomArr);
console.log('最小值:', minVal);
注意事项
- 生成唯一随机数前一定要做边界校验,避免生成数量超过范围可生成的最大不重复数,导致死循环或者报错
- 如果生成的随机数范围很大,比如1到1000000,优先选择Set循环生成法,避免洗牌法占用过多内存
- 提取最小值时,如果数组长度超过10万,建议使用循环遍历的方式,避免扩展运算符导致的栈溢出
- 如果需要多次生成唯一随机数,可以将生成逻辑封装成通用函数,提升代码复用性
JavaScript唯一随机数提取最小值数组操作修改时间:2026-06-19 22:48:34