Cara menggunakan RAMDOM pada JavaScript

Bagaimana saya bisa menghasilkan 8, katakanlah, angka acak unik antara 1 dan 100 menggunakan JavaScript?

var arr = []
while(arr.length < 8){
    var r = Math.floor(Math.random()*100) + 1;
    if(arr.indexOf(r) === -1) arr.Push(r);
}
document.write(arr);

  1. Isi array dengan angka 1 hingga 100.
  2. Kocok .
  3. Ambil 8 elemen pertama dari array yang dihasilkan.

Hasilkan permutasi dari 100 angka dan kemudian pilih secara seri.

Gunakan Knuth Shuffle (alias the Fisher-Yates shuffle) Algoritma .

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;

   }
}

KODE DITIPU DARI Tautan.

EDIT:

Kode yang ditingkatkan:

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

Masalah potensial:

Misalkan kita memiliki array 100 angka {mis. [1,2,3 ... 100]} dan kami berhenti bertukar setelah 8 swap; Maka sebagian besar array waktu akan terlihat seperti {1,2,3,76,5,6,7,8 ,. ..nomor di sini akan dikocok ... 10}.

Karena setiap angka akan ditukar dengan probabilitas 1/100 jadi Prob. menukar 8 angka pertama adalah 8/100 sedangkan prob. menukar 92 lainnya adalah 92/100.

Tetapi jika kita menjalankan algoritma untuk array penuh maka kita yakin (hampir) setiap entri ditukar.

Kalau tidak, kita menghadapi pertanyaan: 8 angka yang harus dipilih?

Teknik-teknik di atas baik jika Anda ingin menghindari perpustakaan, tetapi tergantung jika Anda akan baik-baik saja dengan perpustakaan, saya sarankan memeriksa Peluang untuk menghasilkan hal-hal acak dalam JavaScript.

Khusus untuk menyelesaikan pertanyaan Anda, menggunakan Peluang semudah:

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

Penafian, sebagai penulis Chance, saya agak bias;)

Untuk menghindari kerutan yang panjang dan tidak dapat diandalkan, saya akan melakukan yang berikut ...

  1. Buat array yang berisi angka antara 1 dan 100, secara berurutan.
  2. Hasilkan angka acak antara 1 dan 100
  3. Cari nomor di indeks ini di array dan simpan di hasil Anda
  4. Hapus elemen dari array, membuatnya menjadi lebih pendek
  5. Ulangi dari langkah 2, tetapi gunakan 99 sebagai batas atas angka acak
  6. Ulangi dari langkah 2, tetapi gunakan 98 sebagai batas atas angka acak
  7. Ulangi dari langkah 2, tetapi gunakan 97 sebagai batas atas angka acak
  8. Ulangi dari langkah 2, tetapi gunakan 96 sebagai batas atas angka acak
  9. Ulangi dari langkah 2, tetapi gunakan 95 sebagai batas atas angka acak
  10. Ulangi dari langkah 2, tetapi gunakan 94 sebagai batas atas angka acak
  11. Ulangi dari langkah 2, tetapi gunakan 93 sebagai batas atas angka acak

Voila - tidak ada nomor yang diulang.

Saya dapat memposting beberapa kode aktual nanti, jika ada yang tertarik.

Sunting: Ini mungkin garis kompetitif dalam diri saya tetapi, setelah melihat posting oleh @Alsciende, saya tidak bisa menahan memposting kode yang saya janjikan.

<!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>
    <h2>8 unique random number between 1 and 100</h2>
    <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>

Solusi JS Modern menggunakan Set (dan kasus rata-rata O (n))

const nums = new Set();
while(nums.size !== 8) {
  nums.add(Math.floor(Math.random() * 100) + 1);
}

console.log([...nums]);

Ini adalah fungsi yang sangat umum yang saya tulis untuk menghasilkan bilangan bulat unik/tidak unik untuk sebuah array. Asumsikan parameter terakhir benar dalam skenario ini untuk jawaban ini.

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

Di sini 'tempObj' adalah obj yang sangat berguna karena setiap nomor acak yang dihasilkan akan langsung memeriksa tempObj ini jika kunci itu sudah ada, jika tidak, maka kita mengurangi i per satu karena kita perlu 1 kali dijalankan tambahan karena nomor acak saat ini sudah ada .

Dalam kasus Anda, jalankan yang berikut ini

_arrayRandom(8, 1, 100, true);

Itu saja.

Saya akan melakukan ini:

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;

Mengacak angka dari 1 hingga 100 adalah strategi dasar yang tepat, tetapi jika Anda hanya perlu 8 angka acak, Anda tidak perlu mengacak semua 100 angka.

Saya tidak tahu Javascript dengan baik, tapi saya percaya mudah untuk membuat array 100 nulls dengan cepat. Kemudian, selama 8 putaran, Anda menukar elemen ke-n dari array (n mulai dari 0) dengan elemen yang dipilih secara acak dari n + 1 hingga 99. Tentu saja, elemen apa pun yang belum terisi berarti bahwa elemen tersebut benar-benar indeks asli ditambah 1, jadi itu sepele untuk faktor masuk. Ketika Anda selesai dengan 8 putaran, 8 elemen pertama dari array Anda akan memiliki 8 angka acak.

untuk array dengan lubang seperti ini [,2,,4,,6,7,,] karena masalah saya adalah untuk mengisi lubang ini. Jadi saya memodifikasinya sesuai kebutuhan saya :)

solusi modifikasi berikut ini bekerja untuk saya :)

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

Algoritma permutasi yang sama dengan The Machine Charmer, tetapi dengan implementasi prototyped. Lebih cocok untuk sejumlah besar picks. Menggunakan js 1.7 penugasan pemusnahan jika tersedia.

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

Sunting: Proposisi lain, lebih cocok untuk sejumlah kecil pemetik, berdasarkan jawaban belugabob. Untuk menjamin keunikan, kami menghapus angka yang dipilih dari array.

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

Jawaban terbaik sebelumnya adalah jawabannya oleh sje397. Anda akan mendapatkan angka acak sebaik yang Anda bisa, secepat mungkin.

Solusi saya sangat mirip dengan solusinya. Namun, terkadang Anda menginginkan angka acak dalam urutan acak, dan itulah sebabnya saya memutuskan untuk mengirim jawaban. Selain itu, saya menyediakan fungsi umum.

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

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

lebih pendek dari jawaban lain yang pernah saya lihat

Menggunakan Set adalah pilihan tercepat Anda. Berikut adalah fungsi generik untuk mendapatkan acak unik yang menggunakan generator panggilan balik. Sekarang cepat dan dapat digunakan kembali .

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

Menambahkan versi lain yang lebih baik dari kode yang sama (jawaban yang diterima) dengan fungsi JavaScript 1.6 indexOf. Tidak perlu mengulang melalui seluruh array setiap kali Anda memeriksa duplikat.

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

Versi Javascript yang lebih lama masih dapat menggunakan versi di atas

PS: Mencoba menyarankan pembaruan ke wiki tetapi ditolak. Saya masih berpikir itu mungkin bermanfaat bagi orang lain.

Ini adalah solusi pribadi saya:

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

Ini secara acak menghasilkan 8 nilai array unik (antara 0 dan 7), lalu menampilkannya menggunakan kotak peringatan.

jika Anda membutuhkan yang lebih unik, Anda harus menghasilkan array (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;
}

kode di atas lebih cepat:
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, 98, 76, 80, 56, 90 , 83, 44, 43, 47, 7, 53]

Solusi ini menggunakan hash yang jauh lebih performan O(1) daripada memeriksa apakah berada di dalam array. Ini juga memiliki pemeriksaan ekstra aman. Semoga ini bisa membantu.

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

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

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
}

Ini dapat menangani menghasilkan hingga 20 digit nomor acak UNIK

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

 

Cara menggunakan RAMDOM pada JavaScript

jsFiddle

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

Saya pikir metode ini berbeda dari metode yang diberikan di sebagian besar jawaban, jadi saya pikir saya mungkin menambahkan jawaban di sini (meskipun pertanyaannya diajukan 4 tahun yang lalu).

Kami menghasilkan 100 angka acak, dan menandai masing-masing dengan angka dari 1 hingga 100. Kemudian kami mengurutkan angka-angka acak yang ditandai ini, dan tag-nya dikacak secara acak. Atau, seperti yang diperlukan dalam pertanyaan ini, seseorang dapat menghapus hanya dengan menemukan 8 teratas nomor acak yang ditandai. Menemukan 8 item teratas lebih murah daripada menyortir seluruh array .

Kita harus perhatikan di sini, bahwa algoritma pengurutan memengaruhi algoritma ini. Jika algoritma pengurutan yang digunakan stabil, ada sedikit bias yang mendukung jumlah yang lebih kecil. Idealnya, kami ingin algoritma pengurutan menjadi tidak stabil dan bahkan tidak bias terhadap stabilitas (atau ketidakstabilan) untuk menghasilkan jawaban dengan distribusi probabilitas yang seragam sempurna.

Menerapkan ini sebagai generator membuatnya cukup bagus untuk bekerja dengannya. Catatan, implementasi ini berbeda dari yang membutuhkan seluruh array input untuk dikocok terlebih dahulu. 

Fungsi sample ini bekerja dengan malas, memberi Anda 1 item acak per iterasi hingga N item yang Anda minta. Ini bagus karena jika Anda hanya ingin 3 item dari daftar 1000, Anda tidak harus menyentuh semua 1000 item terlebih dahulu.

// 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]

Saya memilih untuk mengimplementasikan sample dengan cara yang tidak mengubah array input, tetapi Anda dapat dengan mudah berpendapat bahwa implementasi mutasi menguntungkan.

Sebagai contoh, fungsi shuffle mungkin ingin mengubah array input asli. Atau Anda mungkin ingin mengambil sampel dari input yang sama di berbagai waktu, memperbarui input setiap waktu.

// 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 bukan lagi fungsi murni karena mutasi input array, tetapi dalam keadaan tertentu (ditunjukkan di atas) mungkin lebih masuk akal.


Alasan lain saya memilih generator alih-alih fungsi yang baru saja mengembalikan array adalah karena Anda mungkin ingin melanjutkan pengambilan sampel hingga beberapa kondisi tertentu.

Mungkin saya ingin bilangan prima pertama dari daftar 1.000.000 bilangan acak.

  • "Berapa banyak yang harus saya sampel?" - Anda tidak perlu menentukan
  • "Apakah saya harus menemukan semua bilangan prima terlebih dahulu dan kemudian memilih perdana acak?" - Tidak.

Karena kami bekerja dengan generator, tugas ini sepele

const randomPrimeNumber = listOfNumbers => {
  for (let x of sample(Infinity) (listOfNumbers)) {
    if (isPrime(x))
      return x;
  }
  return NaN;
}

Ini akan terus-menerus mengambil 1 nomor acak pada suatu waktu, x, periksa apakah prima, lalu kembalikan x jika ya. Jika daftar angka habis sebelum prime ditemukan, NaN dikembalikan.


Catatan:

Jawaban ini pada awalnya dibagikan pada pertanyaan lain yang ditutup sebagai duplikat dari pertanyaan ini. Karena sangat berbeda dari solusi lain yang disediakan di sini, saya memutuskan untuk membagikannya di sini juga

Pendekatan lain yang lebih sederhana adalah membuat larik 100 item dengan angka naik dan mengurutkannya secara acak. Ini sebenarnya mengarah ke cuplikan yang sangat singkat dan (menurut saya) sederhana.

function randomNumbers() {
  const numbers = [ ...Array(100).keys() ].map(num => num + 1);
  numbers.sort(() => Math.random() - 0.5);
  return numbers.slice(0, 8);
}

Bagaimana kalau menggunakan properti obyek sebagai tabel hash ? Dengan cara ini skenario terbaik Anda adalah dengan hanya mengacak 8 kali. Ini hanya akan efektif jika Anda ingin sebagian kecil dari kisaran angka. Ini juga jauh lebih sedikit memori daripada Fisher-Yates karena Anda tidak perlu mengalokasikan ruang untuk array.

var ht={}, i=rands=8;
while ( i>0 || keys(ht).length<rands) ht[Math.ceil(Math.random()*100)]=i--;
alert(keys(ht));

Saya kemudian menemukan bahwa Object.keys (obj) adalah fitur ECMAScript 5 sehingga di atas cukup banyak tidak berguna di internet sekarang. Jangan takut, karena saya membuatnya ECMAScript 3 kompatibel dengan menambahkan fungsi tombol seperti ini.

if (typeof keys == "undefined") 
{ 
  var keys = function(obj) 
  {
    props=[];
    for (k in ht) if (ht.hasOwnProperty(k)) props.Push(k);
    return props;
  }
}