Gere números aleatórios únicos entre 1 e 100

99

Como posso gerar alguns números aleatórios exclusivos entre 1 e 100 usando JavaScript?

maluco
fonte
19
Não é realmente um idiota, pois está se concentrando em javascript.
dotty de
2
@dotty bem, não há diferença essencial entre fazer isso em Javascript e em qualquer outra linguagem, mas não vou votar para fechar.
Pointy
1
Eu não vou votar para fechar também. Isso é específico o suficiente.
Josh Stodola
1
Há outra maneira mais limpa de fazer isso stackoverflow.com/questions/51898200/…
Huangism

Respostas:

174

Por exemplo: Para gerar 8 números aleatórios exclusivos e armazená-los em uma matriz, você pode simplesmente fazer isso:

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

adam0101
fonte
15
O código real é muito melhor para essas perguntas do que o pseudocódigo;) (excluiu minha resposta que era pseudocódigo ...)
Roman Starkov
3
O pode ser escolhido; use var randomnumber = Math.ceil (Math.random () * 100)
Alsciende
9
-1: este algoritmo é a abordagem ingênua; é muito ineficiente.
Frerich Raabe
39
Uau. Ingênuo parece um pouco forte. Pode não ser a melhor solução, mas é simples, curta, fácil de ver o que está acontecendo e funciona dentro de parâmetros operacionais aceitáveis ​​para o que precisa ser realizado. Para a próxima tarefa. A perfeição é ótima, mas 'pronto' é melhor do que 'perfeito'.
adam0101
4
Existe uma chance de a função retornar um 0 na matriz. De acordo com este link: developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/… , Math.random () Returns a random number between 0 (inclusive) and 1 (exclusive). Se the Math.random()acidentalmente retornar 0, o Math.ceil(0)também será 0, embora a chance seja baixa.
Qian Chen
43
  1. Preencha uma matriz com os números de 1 a 100.
  2. Embaralhe .
  3. Pegue os primeiros 8 elementos da matriz resultante.
ЯegDwight
fonte
8
certamente é mais eficiente ajustar o código para fazer apenas os primeiros 8 embaralhamentos? (e, em seguida, pegue os últimos 8 elementos da matriz semi-embaralhada)
segundo
1
É assim que eu sempre faço também. Então, se eu quisesse dez linhas aleatórias de um arquivo com um monte de linhas, eu quero randlines file | head -10.
tchrist,
1
Acho que é a resposta certa, pois mantém a probabilidade de distrubção, o que a resposta aceita não
roberto tomás
2
E se N = 10 ^ 12? Não é muito eficiente.
shinzou
2
@shinzou no mundo real você não classificaria 10 ^ 12 números usando JavaScript. Uma pergunta tirival exige uma resposta trivial. Não estou aqui para resolver a fome mundial. Estou bem equipado para fazer isso, mas não é disso que se trata.
ЯegDwight
14

Gerar permutação de 100 números e depois 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 {por exemplo, [1,2,3 ... 100]} e paramos de trocar após 8 trocas; então, na maioria das vezes, a matriz será semelhante a {1,2,3,76,5,6,7,8, ... os números aqui serão embaralhados ... 10}.

Porque todos os números serão trocados com probabilidade 1/100, então prob. de trocar os primeiros 8 números é 8/100, enquanto prob. de trocar outros 92 é 92/100.

Mas se executarmos o algoritmo para o array completo, teremos certeza de que (quase) todas as entradas são trocadas.

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

Pratik Deoghare
fonte
5
Essa abordagem é correta, mas subótima: você pode parar de embaralhar após oito trocas, já que precisa de apenas oito números aleatórios. O código acima troca todo o array (neste cenário, 100 elementos).
Frerich Raabe
O código pode ser seriamente melhorado. Os valores de retorno, os efeitos colaterais e o uso de funções são todos muito obscuros. Talvez se você escrever uma função que responda exatamente ao problema original, usando sua função fisherYates, fique mais claro.
Alsciende
1
Resposta atualizada com código melhorado. Além disso, @Frerich Raabe: problema com a parada após oito trocas é mencionado.
Pratik Deoghare
Seu algoritmo de Fisher-Yates está errado. r deve depender de i. Veja meu anwser: stackoverflow.com/questions/2380019/…
Alsciende
Opa desculpe meu erro horrível !! Sua implementação é legal. Gostei. +1. Por favor, deixe-me saber se algo mais está errado com ele.
Pratik Deoghare
11

Solução JS moderna usando Set (e caso médio O (n))

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

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

Alister
fonte
Por que é O (n)? Não pode fazer um loop por um período de tempo arbitrário?
Anthony Wieser
@AnthonyWieser Você está certo, pior caso. Eu estava sugerindo um caso médio desde Set.add é o (1)
Alister
Acho que isso poderia retornar 0 como minha resposta costumava fazer antes de ser alterado para usarMath.floor(Math.random()*100) + 1
adam0101
Muito legal descobrir Setem JS! Porém, essa solução não causaria geração desnecessária de números até que um se encaixasse no requisito de unicidade, especialmente nas últimas iterações, se 8 fosse mais próximo de 100? Assim, acho que prefiro a também elegante resposta sortabaixo.
Gilad Barner
10

As técnicas acima são boas se você quiser evitar uma biblioteca, mas dependendo se você não tiver problemas com uma biblioteca, eu sugiro que você dê uma olhada no 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));
<script src="http://chancejs.com/chance.min.js"></script>

Isenção de responsabilidade, como autor de Chance, sou um pouco tendencioso;)

Victor Quinn
fonte
Vote positivamente
se eu quiser fazer um código (8 strings alfanuméricas aleatórias) para cupons, que deve ser exclusivo, como posso fazer isso com Chance.js? observação: os cupons serão feitos sob demanda, portanto o número de códigos será indefinido
Oscar Yuandinata
@OscarYuandinata é fácil, basta fazer var codes = chance.unique(chance.string, 8)Se você precisa dos códigos extraídos de um pool de caracteres específico, pode especificar assim: chance.unique(chance.string, 8, {pool: "abcd1234"})onde abcd1234 pode ser qualquer caractere que você quiser no pool. Veja chancejs.com/#string
Victor Quinn
@VictorQuinn, desculpe, não fui claro. Quer dizer, o código do cupom será de 8 caracteres alfanuméricos aleatórios, não uma matriz de 8 caracteres alfanuméricos aleatórios. hahaha ..
Oscar Yuandinata
Oh @OscarYuandinata, isso é muito mais fácil heh chance.string({ length: 8 })e se você quiser que apenas alguns caracteres apareçam nessa string, chance.string({ pool: 'abcd1234', length: 8 })que retornaria uma string aleatória de 8 caracteres dos caracteres abcd1234, por exemplo "2c2c44bc" ou "331141cc"
Victor Quinn
8

Para evitar embaralhamento longo e não confiável, eu faria o seguinte ...

  1. Gere uma matriz que contenha o número entre 1 e 100, na ordem.
  2. Gere um número aleatório entre 1 e 100
  3. Procure o número neste índice na matriz e armazene em seus resultados
  4. Remova o elemento da matriz, tornando-o um mais curto
  5. Repita a partir da etapa 2, mas use 99 como o limite superior do número aleatório
  6. Repita a partir da etapa 2, mas use 98 como o limite superior do número aleatório
  7. Repita a partir da etapa 2, mas use 97 como o limite superior do número aleatório
  8. Repita a partir da etapa 2, mas use 96 como o limite superior do número aleatório
  9. Repita a partir da etapa 2, mas use 95 como o limite superior do número aleatório
  10. Repita a partir da etapa 2, mas use 94 como o limite superior do número aleatório
  11. Repita a partir da etapa 2, mas use 93 como o limite superior do número aleatório

Voila - sem números repetidos.

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

Edit: É provavelmente a minha veia competitiva, mas, tendo visto o post de @Alsciende, não pude resistir a postar o código que prometi.

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

Belugabob
fonte
Mas então o seu oitavo número é aleatório de 1 a 92, não de 1 a 100. Se você tivesse que escolher 90 números, seu último número seria escolhido apenas de 1 a 10, não seria?
adam0101
@ adam0101 Não, porque ele remove os números à medida que os escolhe. Portanto, na etapa 5, existem apenas 99 números em sua matriz. @belugabob Você não é mais eficiente do que Knuth Shuffle. Na verdade, a emenda é provavelmente mais cara do que o shuffle (o que é perfeitamente confiável)
Alsciende
@ adam0101: Ele está removendo o elemento escolhido do array (veja a etapa 4 acima), evitando assim que qualquer elemento seja escolhido duas vezes. Ele então usa um limite superior inferior para o próximo número aleatório, simplesmente porque a matriz é mais curta.
Frerich Raabe
@Alsciende, Sim - pensei que haveria uma maneira de fazer isso com mais eficiência usando um shuffle, mas não tinha certeza. Para evitar a exclusão do item da matriz, simplesmente copie a última entrada da matriz (desde que não seja a que você escolheu) para a posição de onde você escolheu.
belugabob
1
O motivo para não diminuir os valores. Comprimento, é que não há garantia de que a redução do comprimento de uma matriz não seja feita pela realocação de memória. Usar maxIndex tem o mesmo efeito, simplesmente ignorando as últimas entradas na matriz, pois elas se tornam irrelevantes.
belugabob
8

Outra abordagem é gerar uma matriz de 100 itens com números crescentes e classificá-la aleatoriamente. Na verdade, isso leva a um trecho muito curto e (na minha opinião) simples.

const numbers = Array(100).fill().map((_, index) => index + 1);
numbers.sort(() => Math.random() - 0.5);
console.log(numbers.slice(0, 8));

Felix Lemke
fonte
Esta é minha resposta favorita de todas elas. Não sei por que obteve apenas 6 votos. Elegante e com boa complexidade (desde que sortseja bem implementado, o que tenho certeza que é).
Gilad Barner
3

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;
quiabo
fonte
3

Esta é uma função muito genérica que escrevi para gerar inteiros únicos / não únicos aleatórios 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 uma vez que cada número aleatório gerado irá verificar diretamente neste tempObj se essa chave já existe, se não, então reduzimos o i em um, pois precisamos de 1 execução extra, uma vez que o número aleatório atual já existe .

No seu caso, execute o seguinte

_arrayRandom(8, 1, 100, true);

Isso é tudo.

Kaizer1v
fonte
o que acontecerá se eu quiser que 0 seja incluído? a linha min = (min) ? min : 1,sempre retornará 1. (portanto, 0 nunca será selecionado)
TBE
Um ponto muito bom. :). Obrigado, eu fiz a alteração apropriada. Agora ele retornará mesmo se você passar em 0.
kaizer1v
2

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.

Não conheço Javascript muito bem, mas acredito que seja fácil criar um array de 100 nulos rapidamente. Então, por 8 rodadas, você troca o enésimo elemento da matriz (n começando em 0) por um elemento selecionado aleatoriamente de n + 1 a 99. Claro, quaisquer elementos não preenchidos ainda significam que o elemento realmente teria sido o índice original mais 1, então isso é trivial para fatorar. Quando você terminar com as 8 rodadas, os primeiros 8 elementos do seu array terão seus 8 números embaralhados.

Randal Schwartz
fonte
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);

mais curta do que outras respostas que eu vi

FFF
fonte
1

Mesmo algoritmo de permutação que 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: Outra proposição, mais adequada para um pequeno número de escolhas, com base 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);
Alsciende
fonte
Boa implementação recursiva - postei uma alternativa, em minha resposta, que não usa splice, pois sinto que esse é um impacto de desempenho evitável (não que o OP tivesse problemas de desempenho)
belugabob
Sua solução é inteligente, mas não vou usá-lo em minha matriz # método de escolher, porque eu não quero isso para ter seus elementos embaralhado quando eu devolvê-lo.
Alsciende
Qual array você não deseja que seja embaralhado, o array 1-100 original ou os resultados? O primeiro não deve importar, pois é um array funcional, e o último, pela natureza do código, sairá em uma ordem aleatória de qualquer maneira. Não tenho certeza se entendi seus motivos.
belugabob
O original. Implementei um método genérico Array # pick, que considero útil. Esta função não sabe se este é um array funcional ou não. Para ser genérico, não altera isso mais do que o necessário.
Alsciende
Mas ainda o altera, mesmo que só um pouco, o que é inevitável ao usar esta técnica.
belugabob
1

para matrizes com buracos como este [,2,,4,,6,7,,] porque meu problema era preencher esses buracos. Então eu modifiquei de acordo com 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<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
Pulkit Chaudhri
fonte
1

A melhor resposta inicial é responder por sje397. Você obterá os melhores números aleatórios que puder, o mais rápido possível.

Minha solução é muito semelhante à solução dele. No entanto, às vezes você quer os números aleatórios em ordem aleatória, e é por isso que decidi postar uma resposta. Além disso, forneço uma função 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));
AndersTornkvist
fonte
1

Aqui está minha versão do ES6 que construí. Tenho certeza que pode ser um pouco mais consolidado.

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

Alex Mireles
fonte
0

Que tal usar as propriedades do objeto como uma tabela hash ? Dessa forma, seu melhor cenário é randomizar apenas 8 vezes. Só será eficaz se você quiser uma pequena parte do intervalo de números. Também consome muito menos memória do que Fisher-Yates, pois você não precisa alocar espaço para um array.

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

Então descobri que Object.keys (obj) é um recurso ECMAScript 5, então o acima é praticamente inútil na internet agora. Não tenha medo, porque eu o tornei compatível com o ECMAScript 3 adicionando uma função de teclas como esta.

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

se precisar de mais exclusivo, você deve gerar uma matriz (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;
}

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]

MajidTaheri
fonte
0

Adicionando outra versão melhor do mesmo código (resposta aceita) com a função indexOf do JavaScript 1.6. Não é necessário fazer um loop por todo o array 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;
}

A versão mais antiga do Javascript ainda pode usar a versão superior

PS: Tentei sugerir uma atualização para o wiki, mas foi rejeitada. Ainda acho que pode ser útil para outros.

software.wikipedia
fonte
0

Esta é a minha solução pessoal:

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

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

Adam Atlas
fonte
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;
}

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

Geramos 100 números aleatórios e marcamos cada um deles com números de 1 a 100. Em seguida, classificamos esses números aleatórios marcados e as marcações são embaralhadas aleatoriamente. Como alternativa, conforme necessário nesta pergunta, pode-se dispensar apenas encontrar os 8 primeiros números aleatórios marcados. Encontrar os 8 itens principais é mais barato do que classificar toda a variedade.

Deve-se notar aqui que o algoritmo de classificação influencia este algoritmo. Se o algoritmo de classificação usado for estável, há uma ligeira tendência a favor de números menores. Idealmente, gostaríamos que o algoritmo de classificação fosse instável e nem mesmo inclinado para a estabilidade (ou instabilidade) para produzir uma resposta com distribuição de probabilidade perfeitamente uniforme.

Kartik Kale
fonte
0

Isso pode lidar com a geração de número aleatório UNIQUE de até 20 dígitos

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

Nofi
fonte
0

Esta solução usa o hash, que tem muito mais desempenho O (1) do que verificar se reside no array. Ele tem verificações de segurança extras também. 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))
RIdotCOM
fonte
0

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

Esta samplefunção funciona preguiçosamente, dando a você 1 item aleatório por iteração até os Nitens que você solicitar. Isso é bom porque se você quiser apenas 3 itens de uma lista de 1000 , não precisará tocar em 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); // 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]

Eu escolhi implementar samplede uma forma que não modifique o array de entrada, mas você poderia facilmente argumentar que uma implementação mutante é favorável.

Por exemplo, a shufflefunção pode desejar alterar a matriz de entrada original. Ou você pode desejar amostrar da mesma entrada em vários momentos, atualizando a entrada a cada vez.

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

samplenão é mais uma função pura por causa da mutação de entrada do array, mas em certas circunstâncias (demonstradas acima) pode fazer mais sentido.


Outra razão pela qual escolhi um gerador em vez de uma função que apenas retorna um array é porque você pode querer continuar a amostragem até alguma condição específica.

Talvez eu queira o primeiro número primo de uma lista de 1.000.000 de números aleatórios.

  • "Quantos devo provar?" - você não tem que especificar
  • "Eu tenho que encontrar todos os primos primeiro e então selecionar um primo aleatório?" - Não.

Como estamos trabalhando com um gerador, essa tarefa é trivial

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

Isso irá amostrar continuamente 1 número aleatório de cada vez x, verificar se é primo e retornar xse for. Se a lista de números se esgotar antes que um primo seja encontrado, NaNserá retornado.


Nota:

Esta resposta foi compartilhada originalmente em outra pergunta que foi fechada como uma duplicata desta. Por ser muito diferente das outras soluções fornecidas aqui, decidi compartilhá-lo aqui também

Obrigado
fonte
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
}
Oscar López
fonte
0

Usar a Seté a opção mais rápida. Aqui está uma função genérica para obter um aleatório exclusivo que usa um gerador de callback. 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))

Steven Spungin
fonte
0

Esta é uma implementação do Fisher Yates / Durstenfeld Shuffle , mas sem a criação real de um array, reduzindo assim a complexidade do espaço ou da memória necessária, quando o tamanho da seleção é pequeno em comparação com o número de elementos disponíveis.

Para escolher 8 números de 100, não é necessário criar uma matriz de 100 elementos.

Supondo que uma matriz seja criada,

  • No final da matriz (100), obtenha um número aleatório ( rnd) de 1 a 100
  • Troque 100 e o número aleatório rnd
  • Repita a etapa 1 com a matriz (99)

Se uma matriz não for criada, um hashMap pode ser usado para lembrar as posições reais trocadas. Quando o segundo número aleatório gerado é igual a um dos números gerados anteriormente, o mapa fornece o valor atual naquela posição ao invés do valor real.

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

O mestre
fonte
0

Aqui está um exemplo de 5 números aleatórios retirados de um intervalo de 0 a 100 (ambos 0 e 100 incluídos) sem duplicação.

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)
Gildniy
fonte
-1

Você também pode fazer isso com um revestimento 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())]

Marcin Król
fonte
Pela pureza de não atribuir nada.
Marcin Król