Làm cách nào để tạo một số số ngẫu nhiên duy nhất từ 1 đến 100 bằng JavaScript?
Làm cách nào để tạo một số số ngẫu nhiên duy nhất từ 1 đến 100 bằng JavaScript?
Câu trả lời:
Ví dụ: Để tạo 8 số ngẫu nhiên duy nhất và lưu trữ chúng vào một mảng, bạn chỉ cần thực hiện điều này:
var arr = [];
while(arr.length < 8){
var r = Math.floor(Math.random() * 100) + 1;
if(arr.indexOf(r) === -1) arr.push(r);
}
console.log(arr);
Returns a random number between 0 (inclusive) and 1 (exclusive)
. Nếu the Math.random()
vô tình trả về 0, Math.ceil(0)
thì cũng là 0, mặc dù cơ hội là thấp.
randlines file | head -10
.
Tạo hoán vị 100 số và sau đó chọn nối tiếp.
Sử dụng Thuật toán xáo trộn Knuth (hay còn gọi là xáo trộn Fisher-Yates) .
JavaScript:
function fisherYates ( myArray,stop_count ) {
var i = myArray.length;
if ( i == 0 ) return false;
int c = 0;
while ( --i ) {
var j = Math.floor( Math.random() * ( i + 1 ) );
var tempi = myArray[i];
var tempj = myArray[j];
myArray[i] = tempj;
myArray[j] = tempi;
// Edited thanks to Frerich Raabe
c++;
if(c == stop_count)return;
}
}
CHỈNH SỬA :
Cải tiến mã:
function fisherYates(myArray,nb_picks)
{
for (i = myArray.length-1; i > 1 ; i--)
{
var r = Math.floor(Math.random()*i);
var t = myArray[i];
myArray[i] = myArray[r];
myArray[r] = t;
}
return myArray.slice(0,nb_picks);
}
Vấn đề tiềm tàng:
Giả sử chúng ta có mảng 100 số {ví dụ [1,2,3 ... 100]} và chúng ta ngừng hoán đổi sau 8 lần hoán đổi; thì hầu hết các mảng thời gian sẽ giống như {1,2,3,76,5,6,7,8, ... các số ở đây sẽ được xáo trộn ... 10}.
Bởi vì mọi số sẽ được hoán đổi với xác suất 1/100 nên prob. hoán đổi 8 số đầu tiên là 8/100 trong khi prob. của hoán đổi 92 khác là 92/100.
Nhưng nếu chúng tôi chạy thuật toán cho toàn mảng thì chúng tôi chắc chắn (hầu như) mọi mục nhập đều được hoán đổi.
Nếu không, chúng ta phải đối mặt với một câu hỏi: chọn 8 số nào?
Giải pháp JS hiện đại sử dụng Set (và trường hợp trung bình O (n))
const nums = new Set();
while(nums.size !== 8) {
nums.add(Math.floor(Math.random() * 100) + 1);
}
console.log([...nums]);
Math.floor(Math.random()*100) + 1
Set
trong JS! Tuy nhiên, giải pháp này sẽ không gây ra việc tạo ra các số không cần thiết cho đến khi một số phù hợp với yêu cầu về tính duy nhất, đặc biệt là trong các lần lặp cuối cùng, nếu 8 gần với 100? Vì vậy, tôi nghĩ rằng tôi thích câu trả lời cũng thanh lịch với sort
bên dưới.
Các kỹ thuật trên là tốt nếu bạn muốn tránh thư viện, nhưng tùy thuộc vào việc bạn có ổn với thư viện hay không, tôi khuyên bạn nên kiểm tra Cơ hội để tạo nội dung ngẫu nhiên trong JavaScript.
Đặc biệt để giải quyết câu hỏi của bạn, sử dụng Chance dễ dàng như sau:
// One line!
var uniques = chance.unique(chance.natural, 8, {min: 1, max: 100});
// Print it out to the document for this snippet so we can see it in action
document.write(JSON.stringify(uniques));
<script src="http://chancejs.com/chance.min.js"></script>
Disclaimer, là tác giả của Chance, tôi hơi thiên vị;)
var codes = chance.unique(chance.string, 8)
Nếu bạn cần mã được lấy từ một nhóm ký tự cụ thể, bạn có thể chỉ định như thế này: chance.unique(chance.string, 8, {pool: "abcd1234"})
trong đó abcd1234 có thể là bất kỳ ký tự nào bạn muốn trong nhóm. Xem luckyjs.com/#string
chance.string({ length: 8 })
và nếu bạn chỉ muốn một số nhân vật xuất hiện trong chuỗi đó, chance.string({ pool: 'abcd1234', length: 8 })
mà sẽ trả về một chuỗi 8 ký tự ngẫu nhiên từ các nhân vật abcd1234, vì vậy ví dụ như "2c2c44bc" hoặc "331141cc"
Để tránh bất kỳ xáo trộn dài và không đáng tin cậy, tôi sẽ làm như sau ...
Thì đấy - không có số lặp lại.
Tôi có thể đăng một số mã thực tế sau, nếu ai đó quan tâm.
Chỉnh sửa: Có lẽ đó là thời kỳ cạnh tranh trong tôi nhưng, khi xem bài đăng của @Alsciende, tôi không thể cưỡng lại việc đăng mã mà tôi đã hứa.
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
<html>
<head>
<title>8 unique random number between 1 and 100</title>
<script type="text/javascript" language="Javascript">
function pick(n, min, max){
var values = [], i = max;
while(i >= min) values.push(i--);
var results = [];
var maxIndex = max;
for(i=1; i <= n; i++){
maxIndex--;
var index = Math.floor(maxIndex * Math.random());
results.push(values[index]);
values[index] = values[maxIndex];
}
return results;
}
function go(){
var running = true;
do{
if(!confirm(pick(8, 1, 100).sort(function(a,b){return a - b;}))){
running = false;
}
}while(running)
}
</script>
</head>
<body>
<h1>8 unique random number between 1 and 100</h1>
<p><button onclick="go()">Click me</button> to start generating numbers.</p>
<p>When the numbers appear, click OK to generate another set, or Cancel to stop.</p>
</body>
Một cách tiếp cận khác là tạo một mảng 100 mục với các số tăng dần và sắp xếp nó một cách ngẫu nhiên. Điều này thực sự dẫn đến một đoạn trích thực sự ngắn và (theo ý kiến của tôi) đơn giản.
const numbers = Array(100).fill().map((_, index) => index + 1);
numbers.sort(() => Math.random() - 0.5);
console.log(numbers.slice(0, 8));
sort
được triển khai tốt, điều mà tôi chắc chắn là như vậy).
Tôi sẽ làm điều này:
function randomInt(min, max) {
return Math.round(min + Math.random()*(max-min));
}
var index = {}, numbers = [];
for (var i=0; i<8; ++i) {
var number;
do {
number = randomInt(1, 100);
} while (index.hasOwnProperty("_"+number));
index["_"+number] = true;
numbers.push(number);
}
delete index;
Đây là một hàm rất chung chung mà tôi đã viết để tạo các số nguyên duy nhất / không duy nhất ngẫu nhiên cho một mảng. Giả sử tham số cuối cùng là đúng trong trường hợp này cho câu trả lời này.
/* Creates an array of random integers between the range specified
len = length of the array you want to generate
min = min value you require
max = max value you require
unique = whether you want unique or not (assume 'true' for this answer)
*/
function _arrayRandom(len, min, max, unique) {
var len = (len) ? len : 10,
min = (min !== undefined) ? min : 1,
max = (max !== undefined) ? max : 100,
unique = (unique) ? unique : false,
toReturn = [], tempObj = {}, i = 0;
if(unique === true) {
for(; i < len; i++) {
var randomInt = Math.floor(Math.random() * ((max - min) + min));
if(tempObj['key_'+ randomInt] === undefined) {
tempObj['key_'+ randomInt] = randomInt;
toReturn.push(randomInt);
} else {
i--;
}
}
} else {
for(; i < len; i++) {
toReturn.push(Math.floor(Math.random() * ((max - min) + min)));
}
}
return toReturn;
}
Ở đây 'tempObj' là một đối tượng rất hữu ích vì mọi số ngẫu nhiên được tạo sẽ trực tiếp kiểm tra trong tempObj này nếu khóa đó đã tồn tại hay chưa, nếu chưa, thì chúng ta giảm i đi một vì chúng ta cần thêm 1 lần chạy nữa vì số ngẫu nhiên hiện tại đã tồn tại .
Trong trường hợp của bạn, hãy chạy như sau
_arrayRandom(8, 1, 100, true);
Đó là tất cả.
min = (min) ? min : 1,
sẽ luôn trả về 1. (để 0 sẽ không bao giờ được chọn)
Xáo trộn các số từ 1 đến 100 là chiến lược cơ bản đúng, nhưng nếu bạn chỉ cần 8 số xáo trộn, không cần phải xáo trộn tất cả 100 số.
Tôi không biết rõ về Javascript, nhưng tôi tin rằng rất dễ dàng để tạo một mảng 100 null một cách nhanh chóng. Sau đó, trong 8 vòng, bạn hoán đổi phần tử thứ n của mảng (n bắt đầu từ 0) với một phần tử được chọn ngẫu nhiên từ n + 1 đến 99. Tất nhiên, bất kỳ phần tử nào chưa được điền có nghĩa là phần tử đó thực sự đã chỉ số ban đầu cộng với 1, do đó, điều đó là nhỏ đối với yếu tố trong. Khi bạn hoàn thành 8 vòng, 8 phần tử đầu tiên của mảng sẽ có 8 số xáo trộn của bạn.
Thuật toán hoán vị tương tự như Máy quyến rũ, nhưng với một triển khai nguyên mẫu. Phù hợp hơn với số lượng lớn các lần chọn. Sử dụng phép gán hủy cấu trúc js 1.7 nếu có.
// swaps elements at index i and j in array this
// swapping is easy on js 1.7 (feature detection)
Array.prototype.swap = (function () {
var i=0, j=1;
try { [i,j]=[j,i]; }
catch (e) {}
if(i) {
return function(i,j) {
[this[i],this[j]] = [this[j],this[i]];
return this;
}
} else {
return function(i,j) {
var temp = this[i];
this[i] = this[j];
this[j] = temp;
return this;
}
}
})();
// shuffles array this
Array.prototype.shuffle = function() {
for(var i=this.length; i>1; i--) {
this.swap(i-1, Math.floor(i*Math.random()));
}
return this;
}
// returns n unique random numbers between min and max
function pick(n, min, max) {
var a = [], i = max;
while(i >= min) a.push(i--);
return a.shuffle().slice(0,n);
}
pick(8,1,100);
Chỉnh sửa: Một đề xuất khác, phù hợp hơn với số lượng lựa chọn nhỏ, dựa trên câu trả lời của belugabob. Để đảm bảo tính duy nhất, chúng tôi xóa các số đã chọn khỏi mảng.
// removes n random elements from array this
// and returns them
Array.prototype.pick = function(n) {
if(!n || !this.length) return [];
var i = Math.floor(this.length*Math.random());
return this.splice(i,1).concat(this.pick(n-1));
}
// returns n unique random numbers between min and max
function pick(n, min, max) {
var a = [], i = max;
while(i >= min) a.push(i--);
return a.pick(n);
}
pick(8,1,100);
cho các mảng có lỗ như thế này [,2,,4,,6,7,,]
vì vấn đề của tôi là lấp đầy các lỗ này. Vì vậy, tôi đã sửa đổi nó theo nhu cầu của mình :)
giải pháp sửa đổi sau đây phù hợp với tôi :)
var arr = [,2,,4,,6,7,,]; //example
while(arr.length < 9){
var randomnumber=Math.floor(Math.random()*9+1);
var found=false;
for(var i=0;i<arr.length;i++){
if(arr[i]==randomnumber){found=true;break;}
}
if(!found)
for(k=0;k<9;k++)
{if(!arr[k]) //if it's empty !!MODIFICATION
{arr[k]=randomnumber; break;}}
}
alert(arr); //outputs on the screen
Câu trả lời trước đó tốt nhất là câu trả lời bằng sje397
. Bạn sẽ nhận được các số ngẫu nhiên tốt nhất có thể, càng nhanh càng tốt.
Giải pháp của tôi rất giống với giải pháp của anh ấy. Tuy nhiên, đôi khi bạn muốn các số ngẫu nhiên theo thứ tự ngẫu nhiên, và đó là lý do tại sao tôi quyết định đăng một câu trả lời. Ngoài ra, tôi cung cấp một chức năng chung.
function selectKOutOfN(k, n) {
if (k>n) throw "k>n";
var selection = [];
var sorted = [];
for (var i = 0; i < k; i++) {
var rand = Math.floor(Math.random()*(n - i));
for (var j = 0; j < i; j++) {
if (sorted[j]<=rand)
rand++;
else
break;
}
selection.push(rand);
sorted.splice(j, 0, rand);
}
return selection;
}
alert(selectKOutOfN(8, 100));
Đây là phiên bản ES6 của tôi mà tôi đã tập hợp cùng nhau. Tôi chắc rằng nó có thể được củng cố hơn một chút.
function randomArray(i, min, max) {
min = Math.ceil(min);
max = Math.floor(max);
let arr = Array.from({length: i}, () => Math.floor(Math.random()* (max - min)) + min);
return arr.sort();
}
let uniqueItems = [...new Set(randomArray(8, 0, 100))]
console.log(uniqueItems);
Làm thế nào về việc sử dụng các thuộc tính đối tượng như một bảng băm ? Theo cách này, kịch bản tốt nhất của bạn là chỉ chọn ngẫu nhiên 8 lần. Nó sẽ chỉ hiệu quả nếu bạn muốn có một phần nhỏ của dãy số. Nó cũng ít tốn bộ nhớ hơn nhiều so với Fisher-Yates vì bạn không phải phân bổ không gian cho một mảng.
var ht={}, i=rands=8;
while ( i>0 || keys(ht).length<rands) ht[Math.ceil(Math.random()*100)]=i--;
alert(keys(ht));
Sau đó, tôi phát hiện ra rằng Object.keys (obj) là một tính năng ECMAScript 5, vì vậy những điều trên là vô dụng trên internets ngay bây giờ. Đừng sợ, vì tôi đã làm cho nó tương thích với ECMAScript 3 bằng cách thêm một chức năng phím như thế này.
if (typeof keys == "undefined")
{
var keys = function(obj)
{
props=[];
for (k in ht) if (ht.hasOwnProperty(k)) props.push(k);
return props;
}
}
nếu bạn cần duy nhất, bạn phải tạo một mảng (1..100).
var arr=[];
function generateRandoms(){
for(var i=1;i<=100;i++) arr.push(i);
}
function extractUniqueRandom()
{
if (arr.length==0) generateRandoms();
var randIndex=Math.floor(arr.length*Math.random());
var result=arr[randIndex];
arr.splice(randIndex,1);
return result;
}
function extractUniqueRandomArray(n)
{
var resultArr=[];
for(var i=0;i<n;i++) resultArr.push(extractUniqueRandom());
return resultArr;
}
mã trên nhanh hơn:
extractUniqueRandomArray (50) => [2, 79, 38, 59, 63, 42, 52, 22, 78, 50, 39, 77, 1, 88, 40, 23, 48, 84, 91, 49, 4, 54, 93, 36, 100, 82, 62, 41, 89, 12, 24, 31, 86, 92, 64, 75, 70, 61, 67, 98, 76, 80, 56, 90, 83, 44, 43, 47, 7, 53]
Thêm một phiên bản tốt hơn của cùng một mã (câu trả lời được chấp nhận) với hàm JavaScript 1.6 indexOf. Không cần phải lặp qua toàn bộ mảng mỗi khi bạn kiểm tra bản sao.
var arr = []
while(arr.length < 8){
var randomnumber=Math.ceil(Math.random()*100)
var found=false;
if(arr.indexOf(randomnumber) > -1){found=true;}
if(!found)arr[arr.length]=randomnumber;
}
Phiên bản cũ hơn của Javascript vẫn có thể sử dụng phiên bản ở trên cùng
Tái bút: Đã cố gắng đề xuất một bản cập nhật cho wiki nhưng nó đã bị từ chối. Tôi vẫn nghĩ rằng nó có thể hữu ích cho những người khác.
Đây là giải pháp cá nhân của tôi:
<script>
var i, k;
var numbers = new Array();
k = Math.floor((Math.random()*8));
numbers[0]=k;
for (var j=1;j<8;j++){
k = Math.floor((Math.random()*8));
i=0;
while (i < numbers.length){
if (numbers[i] == k){
k = Math.floor((Math.random()*8));
i=0;
}else {i++;}
}
numbers[j]=k;
}
for (var j=0;j<8;j++){
alert (numbers[j]);
}
</script>
Nó tạo ngẫu nhiên 8 giá trị mảng duy nhất (từ 0 đến 7), sau đó hiển thị chúng bằng hộp cảnh báo.
function getUniqueRandomNos() {
var indexedArrayOfRandomNo = [];
for (var i = 0; i < 100; i++) {
var randNo = Math.random();
indexedArrayOfRandomNo.push([i, randNo]);
}
indexedArrayOfRandomNo.sort(function (arr1, arr2) {
return arr1[1] - arr2[1]
});
var uniqueRandNoArray = [];
for (i = 0; i < 8; i++) {
uniqueRandNoArray.push(indexedArrayOfRandomNo[i][0]);
}
return uniqueRandNoArray;
}
Tôi nghĩ rằng phương pháp này khác với các phương pháp được đưa ra trong hầu hết các câu trả lời, vì vậy tôi nghĩ mình có thể thêm một câu trả lời ở đây (mặc dù câu hỏi đã được hỏi cách đây 4 năm).
Chúng tôi tạo ra 100 số ngẫu nhiên và gắn thẻ cho mỗi số đó với các số từ 1 đến 100. Sau đó, chúng tôi sắp xếp các số ngẫu nhiên được gắn thẻ này và các thẻ được xáo trộn ngẫu nhiên. Ngoài ra, nếu cần trong câu hỏi này, người ta có thể loại bỏ chỉ cần tìm 8 đầu số ngẫu nhiên được gắn thẻ. Tìm 8 mục hàng đầu rẻ hơn so với sắp xếp toàn bộ mảng.
Một điều phải lưu ý ở đây, rằng thuật toán sắp xếp ảnh hưởng đến thuật toán này. Nếu thuật toán sắp xếp được sử dụng là ổn định, sẽ có một chút sai lệch về số lượng nhỏ hơn. Lý tưởng nhất, chúng tôi muốn thuật toán sắp xếp không ổn định và thậm chí không thiên về ổn định (hoặc không ổn định) để tạo ra một câu trả lời có phân phối xác suất hoàn toàn đồng nhất.
Điều này có thể xử lý việc tạo ra số ngẫu nhiên DUY NHẤT có tới 20 chữ số
JS
var generatedNumbers = [];
function generateRandomNumber(precision) { // input --> number precision in integer
if (precision <= 20) {
var randomNum = Math.round(Math.random().toFixed(precision) * Math.pow(10, precision));
if (generatedNumbers.indexOf(randomNum) > -1) {
if (generatedNumbers.length == Math.pow(10, precision))
return "Generated all values with this precision";
return generateRandomNumber(precision);
} else {
generatedNumbers.push(randomNum);
return randomNum;
}
} else
return "Number Precision shoould not exceed 20";
}
generateRandomNumber(1);
Giải pháp này sử dụng hàm băm có hiệu suất cao hơn O (1) so với việc kiểm tra xem nó có nằm trong mảng hay không. Nó cũng có kiểm tra an toàn bổ sung. Hy vọng nó giúp.
function uniqueArray(minRange, maxRange, arrayLength) {
var arrayLength = (arrayLength) ? arrayLength : 10
var minRange = (minRange !== undefined) ? minRange : 1
var maxRange = (maxRange !== undefined) ? maxRange : 100
var numberOfItemsInArray = 0
var hash = {}
var array = []
if ( arrayLength > (maxRange - minRange) ) throw new Error('Cannot generate unique array: Array length too high')
while(numberOfItemsInArray < arrayLength){
// var randomNumber = Math.floor(Math.random() * (maxRange - minRange + 1) + minRange)
// following line used for performance benefits
var randomNumber = (Math.random() * (maxRange - minRange + 1) + minRange) << 0
if (!hash[randomNumber]) {
hash[randomNumber] = true
array.push(randomNumber)
numberOfItemsInArray++
}
}
return array
}
document.write(uniqueArray(1, 100, 8))
Thực hiện điều này như một trình tạo làm cho nó khá tốt để làm việc với. Lưu ý, cách triển khai này khác với cách triển khai yêu cầu toàn bộ mảng đầu vào được xáo trộn trước.
sample
Chức năng này hoạt động một cách lười biếng, cung cấp cho bạn 1 mục ngẫu nhiên mỗi lần lặp cho đếnN
các mục bạn yêu cầu. Điều này rất hay vì nếu bạn chỉ muốn 3 mục từ danh sách 1000 , bạn không cần phải chạm vào tất cả 1000 mục trước.
// sample :: Integer -> [a] -> [a]
const sample = n => function* (xs) {
let ys = xs.slice(0);
let len = xs.length;
while (n > 0 && len > 0) {
let i = (Math.random() * len) >> 0;
yield ys.splice(i,1)[0];
n--; len--;
}
}
// example inputs
let items = ['a', 'b', 'c', 'd', 'e', 'f', 'g'];
let numbers = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
// get 3 random items
for (let i of sample(3) (items))
console.log(i); // f g c
// partial application
const lotto = sample(3);
for (let i of lotto(numbers))
console.log(i); // 3 8 7
// shuffle an array
const shuffle = xs => Array.from(sample (Infinity) (xs))
console.log(shuffle(items)) // [b c g f d e a]
Tôi đã chọn triển khai sample
theo cách không làm thay đổi mảng đầu vào, nhưng bạn có thể dễ dàng tranh luận rằng việc triển khai thay đổi là thuận lợi.
Ví dụ, shuffle
hàm có thể muốn thay đổi mảng đầu vào ban đầu. Hoặc bạn có thể muốn lấy mẫu từ cùng một đầu vào vào nhiều thời điểm khác nhau, cập nhật đầu vào mỗi lần.
// sample :: Integer -> [a] -> [a]
const sample = n => function* (xs) {
let len = xs.length;
while (n > 0 && len > 0) {
let i = (Math.random() * len) >> 0;
yield xs.splice(i,1)[0];
n--; len--;
}
}
// deal :: [Card] -> [Card]
const deal = xs => Array.from(sample (2) (xs));
// setup a deck of cards (13 in this case)
// cards :: [Card]
let cards = 'A234567890JQK'.split('');
// deal 6 players 2 cards each
// players :: [[Card]]
let players = Array.from(Array(6), $=> deal(cards))
console.log(players);
// [K, J], [6, 0], [2, 8], [Q, 7], [5, 4], [9, A]
// `cards` has been mutated. only 1 card remains in the deck
console.log(cards);
// [3]
sample
không còn là một hàm thuần túy do đột biến đầu vào của mảng, nhưng trong một số trường hợp nhất định (đã trình bày ở trên), nó có thể có ý nghĩa hơn.
Một lý do khác khiến tôi chọn trình tạo thay vì một hàm chỉ trả về một mảng là vì bạn có thể muốn tiếp tục lấy mẫu cho đến khi có một số điều kiện cụ thể.
Có lẽ tôi muốn số nguyên tố đầu tiên từ danh sách 1.000.000 số ngẫu nhiên.
Bởi vì chúng tôi đang làm việc với một trình tạo, tác vụ này là nhỏ
const randomPrimeNumber = listOfNumbers => {
for (let x of sample(Infinity) (listOfNumbers)) {
if (isPrime(x))
return x;
}
return NaN;
}
Thao tác này sẽ liên tục lấy mẫu 1 số ngẫu nhiên tại một thời điểm x
, hãy kiểm tra xem nó có phải là số nguyên tố hay không, sau đó trả về x
nếu đúng. Nếu danh sách các số hết trước khi tìm thấy một số nguyên tố, NaN
sẽ được trả về.
Ghi chú:
Câu trả lời này ban đầu được chia sẻ trên một câu hỏi khác đã bị đóng lại là bản sao của câu hỏi này. Bởi vì nó rất khác với các giải pháp khác được cung cấp ở đây, tôi cũng quyết định chia sẻ nó ở đây
getRandom (min, max) {
return Math.floor(Math.random() * (max - min)) + min
}
getNRandom (min, max, n) {
const numbers = []
if (min > max) {
return new Error('Max is gt min')
}
if (min === max) {
return [min]
}
if ((max - min) >= n) {
while (numbers.length < n) {
let rand = this.getRandom(min, max + 1)
if (numbers.indexOf(rand) === -1) {
numbers.push(rand)
}
}
}
if ((max - min) < n) {
for (let i = min; i <= max; i++) {
numbers.push(i)
}
}
return numbers
}
Sử dụng a Set
là lựa chọn nhanh nhất của bạn. Đây là một hàm chung để lấy một ngẫu nhiên duy nhất sử dụng trình tạo lệnh gọi lại. Bây giờ nó nhanh chóng và có thể tái sử dụng .
// Get a unique 'anything'
let unique = new Set()
function getUnique(generator) {
let number = generator()
while (!unique.add(number)) {
number = generator()
}
return number;
}
// The generator. Return anything, not just numbers.
const between_1_100 = () => 1 + Math.floor(Math.random() * 100)
// Test it
for (var i = 0; i < 8; i++) {
const aNumber = getUnique(between_1_100)
}
// Dump the 'stored numbers'
console.log(Array.from(unique))
Đây là một triển khai của Fisher Yates / Durstenfeld Shuffle , nhưng không tạo mảng thực sự, do đó làm giảm độ phức tạp của không gian hoặc bộ nhớ cần thiết, khi kích thước vùng chọn nhỏ so với số lượng phần tử có sẵn.
Để chọn 8 số từ 100, không cần thiết phải tạo một mảng 100 phần tử.
Giả sử một mảng được tạo,
rnd
) từ 1 đến 100 rnd
Nếu một mảng không được tạo, một Bản đồ băm có thể được sử dụng để ghi nhớ các vị trí được hoán đổi thực tế. Khi số ngẫu nhiên thứ hai được tạo bằng một trong các số được tạo trước đó, bản đồ cung cấp giá trị hiện tại ở vị trí đó chứ không phải giá trị thực.
const getRandom_ = (start, end) => {
return Math.floor(Math.random() * (end - start + 1)) + start;
};
const getRealValue_ = (map, rnd) => {
if (map.has(rnd)) {
return getRealValue_(map, map.get(rnd));
} else {
return rnd;
}
};
const getRandomNumbers = (n, start, end) => {
const out = new Map();
while (n--) {
const rnd = getRandom_(start, end--);
out.set(getRealValue_(out, rnd), end + 1);
}
return [...out.keys()];
};
console.info(getRandomNumbers(8, 1, 100));
console.info(getRandomNumbers(8, 1, Math.pow(10, 12)));
console.info(getRandomNumbers(800000, 1, Math.pow(10, 15)));
Dưới đây là một ví dụ về 5 số ngẫu nhiên được lấy từ phạm vi từ 0 đến 100 (bao gồm cả 0 và 100) mà không có sự trùng lặp.
let finals = [];
const count = 5; // Considering 5 numbers
const max = 100;
for(let i = 0; i < max; i++){
const rand = Math.round(Math.random() * max);
!finals.includes(rand) && finals.push(rand)
}
finals = finals.slice(0, count)
Bạn cũng có thể làm điều đó với một lớp lót như thế này:
[...((add, set) => add(set, add))((set, add) => set.size < 8 ? add(set.add(Math.floor(Math.random()*100) + 1), add) : set, new Set())]