Gere números randoms únicos entre 1 e 100

Como posso gerar 8 números randoms únicos entre 1 e 100 usando JavaScript?

    var arr = [] while(arr.length < 8){ var randomnumber = Math.floor(Math.random()*100) + 1; if(arr.indexOf(randomnumber) > -1) continue; arr[arr.length] = randomnumber; } document.write(arr); 
    1. Preencher uma matriz com os números de 1 a 100.
    2. Embaralhe-o
    3. Pegue os primeiros 8 elementos da matriz resultante.

    Gere a permutação de 100 números e, em seguida, escolha em série.

    Use o Algoritmo Knuth Shuffle (também conhecido como Fisher-Yates shuffle) .

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

    CÓDIGO COPIADO DO LINK.

    EDITAR :

    Código aprimorado:

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

    Problema potencial:

    Suponha que temos um array de 100 números {eg [1,2,3 … 100]} e paramos de trocar depois de 8 swaps; então a maior parte das vezes a matriz será parecida com {1,2,3,76,5,6,7,8, … os números aqui serão embaralhados … 10}.

    Porque cada número será trocado com probabilidade 1/100, então prob. de trocar primeiros 8 números é 8/100 enquanto prob. de trocar outro 92 é 92/100.

    Mas se nós executarmos o algoritmo para array completo, então temos certeza que (quase) todas as inputs são trocadas.

    Caso contrário, nos deparamos com uma pergunta: quais 8 números para escolher?

    As técnicas acima são boas se você quiser evitar uma biblioteca, mas dependendo se você estiver bem com uma biblioteca, eu sugiro verificar Chance para gerar coisas aleatórias em JavaScript.

    Especificamente para resolver sua dúvida, usar o Chance é tão fácil quanto:

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

    Para evitar shuffles longos e não confiáveis, eu faria o seguinte …

    1. Gere uma matriz que contém o número entre 1 e 100, em ordem.
    2. Gere um número random entre 1 e 100
    3. Procure o número nesse índice na matriz e armazene seus resultados
    4. Remova o elemnt do array, tornando-o mais curto
    5. Repita a partir do passo 2, mas use 99 como o limite superior do número random
    6. Repita a partir do passo 2, mas use 98 como o limite superior do número random
    7. Repita a partir do passo 2, mas use 97 como o limite superior do número random
    8. Repita a partir do passo 2, mas use 96 como o limite superior do número random
    9. Repita a partir do passo 2, mas use 95 como o limite superior do número random
    10. Repita a partir do passo 2, mas use 94 como o limite superior do número random
    11. Repita a partir do passo 2, mas use 93 como o limite superior do número random

    Voila – sem números repetidos.

    Eu posso postar algum código real mais tarde, se alguém estiver interessado.

    Edit: É provavelmente a raia competitiva em mim, mas, tendo visto o post do @Alsciende, eu não pude resistir a postar o código que prometi.

     < !DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">   8 unique random number between 1 and 100    

    8 unique random number between 1 and 100

    to start generating numbers.

    When the numbers appear, click OK to generate another set, or Cancel to stop.

    Eu faria isso:

     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; 

    Esta é uma function muito genérica que escrevi para gerar inteiros únicos / não exclusivos randoms para uma matriz. Suponha que o último parâmetro seja verdadeiro neste cenário para esta resposta.

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

    Aqui o 'tempObj' é um obj muito útil já que todo número random gerado irá verificar diretamente neste tempObj se essa chave já existe, se não, então reduzimos o i por um já que precisamos de 1 run extra já que o atual número random já existe .

    No seu caso, execute o seguinte

     _arrayRandom(8, 1, 100, true); 

    Isso é tudo.

    Solução JS moderna: (e está em O (n))

     const nums = new Set(); while(nums.size !== 8) { nums.add(Math.ceil(Math.random() * 100)); } console.log([...nums]); 

    Embaralhar os números de 1 a 100 é a estratégia básica correta, mas se você precisar de apenas 8 números embaralhados, não há necessidade de embaralhar todos os 100 números.

    Eu não conheço Javascript muito bem, mas acredito que é fácil criar uma matriz de 100 nulos rapidamente. Então, por 8 rodadas, você troca o n’ésimo elemento da matriz (n iniciando em 0) com um elemento selecionado aleatoriamente de n + 1 a 99. Naturalmente, qualquer elemento não preenchido ainda significa que o elemento realmente teria sido o índice original mais 1, de modo que é trivial para fatorar. Quando você terminar com as 8 rodadas, os primeiros 8 elementos da sua matriz terão seus 8 números embaralhados.

    O mesmo algoritmo de permutação do The Machine Charmer, mas com uma implementação prototipada. Mais adequado para um grande número de escolhas. Usa atribuição de desestruturação js 1.7, se disponível.

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

    Edit: Uma outra proposta, mais adequada ao pequeno número de escolhas, baseada na resposta do belugabob. Para garantir a exclusividade, removemos os números escolhidos da matriz.

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

    para arrays com buracos como este [,2,,4,,6,7,,] porque o meu problema era preencher esses buracos. Então eu modifiquei conforme minha necessidade 🙂

    a seguinte solução modificada funcionou para mim 🙂

     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 

    A melhor resposta anterior é a resposta por sje397 . Você terá números randoms tão bons quanto puder, o mais rápido possível.

    Minha solução é muito semelhante à sua solução. No entanto, às vezes você quer os números randoms em ordem aleatória, e é por isso que decidi postar uma resposta. Além disso, forneço uma function geral.

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

    mais curto do que outras respostas que eu vi

    Que tal usar propriedades de objects como uma tabela de hash ? Desta forma, seu melhor cenário é apenas randomizar 8 vezes. Só seria eficaz se você quiser uma pequena parte do intervalo de números. Também é muito menos intensivo em memory do que o Fisher-Yates, porque você não precisa alocar espaço para um array.

     var ht={}, i=rands=8; while ( i>0 || keys(ht).length 

    Descobri então que Object.keys (obj) é um recurso do ECMAScript 5, portanto, o acima é praticamente inútil nas internets agora. Não tenha medo, porque tornei o ECMAScript 3 compatível adicionando uma function de teclas como essa.

     if (typeof keys == "undefined") { var keys = function(obj) { props=[]; for (k in ht) if (ht.hasOwnProperty(k)) props.push(k); return props; } } 
     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 

    Se você precisar de mais exclusivo, você deve gerar um 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 

    o código acima é mais rápido:
    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]

    Adicionando outra versão melhor do mesmo código (resposta aceita) com a function indexOf do JavaScript 1.6. Não é necessário fazer um loop por toda a matriz toda vez que você estiver verificando a duplicata.

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

    Versão mais antiga do Javascript ainda pode usar a versão no topo

    PS: Tentei sugerir uma atualização para o wiki, mas foi rejeitado. Eu ainda acho que pode ser útil para os outros.

    Esta é minha solução pessoal:

      

    Ele gera aleatoriamente 8 valores de matriz exclusivos (entre 0 e 7) e os exibe usando uma checkbox de alerta.

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

    Eu acho que esse método é diferente dos methods dados na maioria das respostas, então eu pensei em adicionar uma resposta aqui (embora a pergunta tenha sido feita há 4 anos atrás).

    Geramos 100 números randoms e marcamos cada um deles com números de 1 a 100. Depois, classificamos esses números randoms marcados e as tags são embaralhadas aleatoriamente. Alternativamente, conforme necessário nesta questão, pode-se acabar apenas com o top 8 dos números randoms marcados. Encontrar os 8 principais itens é mais barato do que ordenar toda a matriz.

    Deve-se notar aqui que o algoritmo de sorting influencia esse algoritmo. Se o algoritmo de ordenação usado é estável, existe um ligeiro viés em favor de números menores. Idealmente, gostaríamos que o algoritmo de ordenação fosse instável e nem inclinado à estabilidade (ou instabilidade) para produzir uma resposta com distribuição de probabilidade perfeitamente uniforme.

    Isso pode manipular a geração de até 20 dígitos UNIQUE número random

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

    insira a descrição da imagem aqui

    jsFiddle

    Esta solução usa o hash que tem muito mais desempenho (1) do que verificar se o array está no array. Também tem cheques extras seguros. Espero que ajude.

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

    Implementar isso como um gerador faz com que seja muito bom trabalhar com ele. Observe que essa implementação difere daquelas que exigem que toda a matriz de input seja embaralhada primeiro.

    Esta function de sample funciona preguiçosamente, dando a você 1 item random por iteração até N itens solicitados. Isso é bom porque se você quer apenas 3 itens de uma lista de 1000 , você não precisa tocar todos os 1000 itens primeiro.

     // 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); // fgc // 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)) // [bcgfdea] 

    Você também pode fazer isso com um liner como este:

    [...((add, set) => add(set, add))((set, add) => set.size < 8 ? add(set.add(Math.floor(Math.random()*100) + 1), add) : set, new Set())]

     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 } 

    Outra abordagem mais simples é gerar um array de 100 itens com números ascendentes e classificá-lo aleatoriamente. Isso leva a um trecho realmente curto e (na minha opinião) simples.

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

    Usar um Set é sua opção mais rápida. Aqui está uma function genérica para obter um random exclusivo que usa um gerador de retorno de chamada. Agora é rápido e reutilizável .

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