Tạo các số ngẫu nhiên duy nhất từ ​​1 đến 100


98

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?


19
Không hẳn là một bản dupe vì điều này đang tập trung vào javascript.
dotty

2
@dotty cũng không có sự khác biệt cơ bản giữa thực hiện điều này trong Javascript và thực hiện nó bằng bất kỳ ngôn ngữ nào khác, nhưng tôi sẽ không bỏ phiếu để đóng.
Pointy

1
Tôi cũng sẽ không bỏ phiếu để đóng. Điều này là đủ cụ thể.
Josh Stodola


1
Có một cách khác rõ ràng hơn để thực hiện điều này stackoverflow.com/questions/51898200/…
Huangism

Câu trả lời:


173

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);


15
Mã thực tế là tốt hơn rất nhiều cho các câu hỏi như vậy so với giả;) (xóa câu trả lời của tôi đó là giả ...)
La Mã Starkov

3
O có thể được chọn; sử dụng var randomnumber = Math.ceil (Math.random () * 100)
Alsciende

9
-1: thuật toán này là cách tiếp cận ngây thơ; nó rất kém hiệu quả.
Frerich Raabe

39
Chà. Ngây thơ có vẻ hơi mạnh mẽ. Nó có thể không phải là giải pháp tốt nhất, nhưng nó đơn giản, ngắn gọn, dễ hiểu những gì đang xảy ra và chạy trong các thông số hoạt động chấp nhận được cho những gì cần phải hoàn thành. Vào nhiệm vụ tiếp theo. Hoàn hảo là tuyệt vời, nhưng 'hoàn thành' sẽ tốt hơn 'hoàn hảo'.
adam0101

4
Có khả năng hàm trả về giá trị 0 trong mảng. Theo liên kết này: developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/… , Math.random () 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.
Qian Chen

43
  1. Điền một mảng với các số từ 1 đến 100.
  2. Xáo trộn nó .
  3. Lấy 8 phần tử đầu tiên của mảng kết quả.

8
chắc chắn sẽ hiệu quả hơn khi chỉnh sửa mã để chỉ thực hiện 8 lần xáo trộn đầu tiên? (và sau đó lấy 8 phần tử cuối cùng của mảng bán trộn)
thứ hai vào

1
Đây là cách tôi luôn làm. Vì vậy, nếu tôi muốn có mười dòng ngẫu nhiên từ một tệp với một loạt các dòng trong đó, tôi sẽ làm randlines file | head -10.
tchrist

1
Tôi nghĩ là được câu trả lời thích hợp, bởi vì nó duy trì distrubtion xác suất, mà câu trả lời được chấp nhận không
roberto Tomás

2
Nếu N = 10 ^ 12 thì sao? Không hiệu quả lắm.
shinzou

2
@shinzou trong thế giới thực, bạn sẽ không sắp xếp 10 ^ 12 số bằng JavaScript. Một câu hỏi tirival đòi hỏi một câu trả lời tầm thường. Tôi không ở đây để giải quyết nạn đói trên thế giới. Tôi được trang bị tốt để làm điều đó, nhưng đó không phải là điều mà câu hỏi đặt ra.
ЯegDwight

14

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;

   }
}

MÃ ĐƯỢC SAO CHÉP TỪ LIÊN KẾT.

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?


5
Cách tiếp cận này đúng nhưng không tối ưu: bạn có thể ngừng xáo trộn sau tám lần hoán đổi, vì bạn chỉ cần tám số ngẫu nhiên. Đoạn mã trên hoán đổi toàn bộ mảng (trong trường hợp này là 100 phần tử).
Frerich Raabe

Mã có thể được cải thiện nghiêm túc. Giá trị trả về, hiệu ứng phụ và cách sử dụng chức năng đều là IMO thực sự mờ. Có thể nếu bạn viết một hàm trả lời chính xác vấn đề ban đầu bằng cách sử dụng hàm FisherYates của bạn, nó sẽ rõ ràng hơn.
Alsciende

1
Câu trả lời được cập nhật với mã cải tiến. Ngoài ra, @Frerich Raabe: vấn đề dừng lại sau tám lần hoán đổi được đề cập.
Pratik Deoghare

Thuật toán Fisher-Yates của bạn sai. r nên phụ thuộc vào tôi. Xem anwser của tôi: stackoverflow.com/questions/2380019/…
Alsciende

Rất tiếc, xin lỗi vì sai lầm khủng khiếp của tôi !! Việc triển khai của bạn thật tuyệt. Thích nó. +1. Xin vui lòng cho tôi biết nếu có bất cứ điều gì khác sai với nó.
Pratik Deoghare

11

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]);


Tại sao lại là O (n)? Nó không thể lặp lại trong một khoảng thời gian tùy ý?
Anthony Wieser

@AnthonyWieser Bạn nói đúng, trường hợp xấu nhất. Tôi đã ngụ ý trường hợp trung bình kể từ Set.add là o (1)
Alister

Tôi nghĩ rằng điều này có thể trở về 0 như câu trả lời của tôi sử dụng để trước khi nó được thay đổi để sử dụngMath.floor(Math.random()*100) + 1
adam0101

Rất thú vị để khám phá Settrong 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 sortbên dưới.
Gilad Barner

10

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ị;)


Ủng hộ vì tôi chưa bao giờ thấy đoạn mã chạy trước đây
lướt web

nếu tôi muốn tạo mã (8 chuỗi chữ và số ngẫu nhiên) cho các phiếu giảm giá, mã này phải là duy nhất, làm cách nào tôi có thể làm điều đó với Chance.js? lưu ý: phiếu giảm giá sẽ được thực hiện theo yêu cầu, vì vậy số lượng mã sẽ không có thời hạn
Oscar Yuandinata

@OscarYuandinata thật dễ dàng, chỉ cần làm 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
Victor Quinn

@VictorQuinn, xin lỗi tôi không nói rõ. Ý tôi là mã phiếu thưởng sẽ là chuỗi chữ số ngẫu nhiên 8 ký tự, không phải là một mảng gồm 8 chuỗi chữ số ngẫu nhiên. hahaha ..
Oscar Yuandinata

Oh @OscarYuandinata đó là heh xa dễ dàng hơn 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"
Victor Quinn

8

Để 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 ...

  1. Tạo một mảng có chứa số từ 1 đến 100, theo thứ tự.
  2. Tạo một số ngẫu nhiên từ 1 đến 100
  3. Tra cứu số tại chỉ mục này trong mảng và lưu trữ trong kết quả của bạn
  4. Loại bỏ elemnt khỏi mảng, làm cho nó ngắn hơn
  5. Lặp lại từ bước 2, nhưng sử dụng 99 làm giới hạn trên của số ngẫu nhiên
  6. Lặp lại từ bước 2, nhưng sử dụng 98 làm giới hạn trên của số ngẫu nhiên
  7. Lặp lại từ bước 2, nhưng sử dụng 97 làm giới hạn trên của số ngẫu nhiên
  8. Lặp lại từ bước 2, nhưng sử dụng 96 làm giới hạn trên của số ngẫu nhiên
  9. Lặp lại từ bước 2, nhưng sử dụng 95 làm giới hạn trên của số ngẫu nhiên
  10. Lặp lại từ bước 2, nhưng sử dụng 94 làm giới hạn trên của số ngẫu nhiên
  11. Lặp lại từ bước 2, nhưng sử dụng 93 làm giới hạn trên của số ngẫu nhiên

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>


Nhưng sau đó số thứ tám của bạn là ngẫu nhiên từ 1 đến 92, không phải 1 đến 100. Nếu bạn phải chọn 90 số, số cuối cùng của bạn sẽ chỉ được chọn từ 1 đến 10, phải không?
adam0101

@ adam0101 Không, vì anh ấy xóa các số khi chọn chúng. Vì vậy, ở bước 5, chỉ có 99 số trong mảng của anh ta. @belugabob Bạn không hiệu quả hơn Knuth Shuffle. Trong thực tế, các mối nối có lẽ là đắt hơn shuffle (đó là hoàn toàn đáng tin cậy)
Alsciende

@ adam0101: Anh ấy đang xóa phần tử đã chọn khỏi mảng (xem bước 4 ở trên), do đó tránh việc bất kỳ phần tử nào được chọn hai lần. Sau đó, anh ta sử dụng giới hạn trên thấp hơn cho số ngẫu nhiên tiếp theo, đơn giản vì mảng ngắn hơn.
Frerich Raabe

@Alsciende, Có - nghĩ rằng sẽ có cách thực hiện điều này hiệu quả hơn bằng cách sử dụng xáo trộn, nhưng không hoàn toàn chắc chắn. Để tránh xóa mục khỏi mảng, chỉ cần sao chép mục nhập cuối cùng từ mảng (miễn là nó không phải là mục bạn đã chọn) vào vị trí bạn đã chọn.
belugabob

1
Lý do không giảm giá trị.length là không có gì đảm bảo rằng việc giảm độ dài của một mảng không được thực hiện bằng cách phân bổ lại bộ nhớ. Sử dụng maxIndex cũng có tác dụng tương tự, bằng cách đơn giản bỏ qua các mục nhập cuối cùng trong mảng, vì chúng trở nên không liên quan.
belugabob

8

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));


Đây là câu trả lời yêu thích của tôi trong số họ. Dunno tại sao nó chỉ nhận được 6 phiếu bầu. Thanh lịch và có độ phức tạp tốt (được cung cấp sortđược triển khai tốt, điều mà tôi chắc chắn là như vậy).
Gilad Barner

3

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;

3

Đâ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ả.


điều gì sẽ xảy ra nếu tôi muốn đưa số 0 vào? dòng min = (min) ? min : 1,sẽ luôn trả về 1. (để 0 sẽ không bao giờ được chọn)
TBE

Một điểm rất tốt. :). Cảm ơn bạn, tôi đã thực hiện thay đổi thích hợp. Bây giờ nó sẽ trở lại ngay cả khi bạn vượt qua trong một 0.
kaizer1v

2

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.


2
var arr = []
while(arr.length < 8){
  var randomnumber=Math.ceil(Math.random()*100)
  if(arr.indexOf(randomnumber) === -1){arr.push(randomnumber)}  
}
document.write(arr);

ngắn hơn các câu trả lời khác mà tôi đã thấy


1

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);

Đệ quy thực hiện Nice - Tôi đã đăng một sự thay thế, trong câu trả lời của tôi, mà không sử dụng mối nối, như tôi cảm thấy rằng đây là một màn trình diễn hit tránh được (Không phải là OP có bất kỳ vấn đề với hiệu suất)
belugabob

Giải pháp của bạn rất thông minh, nhưng tôi sẽ không sử dụng nó trong phương pháp Array # pick của mình vì tôi không muốn điều này có các phần tử của nó bị xáo trộn khi tôi trả lại.
Alsciende

Bạn không muốn xáo trộn mảng nào, mảng 1-100 ban đầu hoặc kết quả? Cái thứ nhất không quan trọng, vì nó là một mảng đang hoạt động, và cái thứ hai, theo bản chất của mã, dù sao cũng sẽ xuất hiện theo thứ tự ngẫu nhiên. Không hoàn toàn chắc chắn rằng tôi hiểu lý do của bạn.
belugabob

Bản gốc. Tôi đã triển khai một phương pháp Array # pick chung, mà tôi thấy hữu ích. Hàm này không biết đây có phải là một mảng đang hoạt động hay không. Nói chung, nó không làm thay đổi điều này nhiều hơn mức cần thiết.
Alsciende

Nhưng nó vẫn làm thay đổi nó, ngay cả khi chỉ một chút, điều không thể tránh khỏi khi sử dụng kỹ thuật này.
belugabob

1

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

1

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));

1

Đâ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);


0

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;
  }
}

0
var bombout=0;
var checkArr=[];
var arr=[];
while(arr.length < 8 && bombout<100){
  bombout++;
  var randomNumber=Math.ceil(Math.random()*100);
  if(typeof checkArr[randomNumber] == "undefined"){
    checkArr[randomNumber]=1;
    arr.push(randomNumber);
  }
}​

// untested - hence bombout

0

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]


0

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.


0

Đâ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.


0
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.


0

Đ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);

nhập mô tả hình ảnh ở đây

jsFiddle


0

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))

0

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.

sampleChứ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 đến Ncá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 sampletheo 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ụ, shufflehà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]

samplekhô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.

  • "Tôi nên lấy mẫu bao nhiêu?" - bạn không cần phải chỉ định
  • "Tôi có phải tìm tất cả các số nguyên tố trước rồi chọn một số nguyên tố ngẫu nhiên không?" - Không.

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ề xnế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ố, NaNsẽ đượ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


0
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
}

0

Sử dụng a Setlà 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óngcó 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))


0

Đâ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,

  • Từ cuối mảng (100), nhận số ngẫu nhiên ( rnd) từ 1 đến 100
  • Hoán đổi 100 và số ngẫu nhiên rnd
  • Lặp lại bước 1 với mảng (99)

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)));


0

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)

-1

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())]


Vì sự trong sáng không gán ghép bất cứ điều gì.
Marcin Król
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.