Generate multiple random numbers without repetition

I've made some attempts to make a function that returns random numbers that don't repeat, I've made a few attempts but none were successful, if you can show me a function that does that thank you.

Author: hkotsubo, 2014-03-23

4 answers

The solution that comes to me is to create an array and add to it the values already created/drawn, and look in the array if the value already exists before exporting a new one.

This solution allows you to draw values one by one as well as to draw them all at once.

var sorteados = [];
var valorMaximo = 1000;

function criarUnico() {
    if (sorteados.length == valorMaximo) {
        if (confirm('Já não há mais! Quer recomeçar?')) sorteados = [];
        else return;
    }
    var sugestao = Math.ceil(Math.random() * valorMaximo); // Escolher um numero ao acaso
    while (sorteados.indexOf(sugestao) >= 0) {  // Enquanto o numero já existir, escolher outro
        sugestao = Math.ceil(Math.random() * valorMaximo);
    }
    sorteados.push(sugestao); // adicionar este numero à array de numeros sorteados para futura referência
    return sugestao; // devolver o numero único
}

Thus, to draw a number just use:

criarUnico(); // que retorna um valor único

Example

 15
Author: Sergio, 2014-03-24 13:19:01

First, generate an ordered list, in this example from 1 to 1000:

var maximo = 1000;

var i, arr = [];
for (i = 0; i < maximo; i++) {
   arr[i] = i + 1;
}

Then shuffle the numbers inside this array:

var p, n, tmp;
for (p = arr.length; p;) {
    n = Math.random() * p-- | 0;
    tmp = arr[n];
    arr[n] = arr[p];
    arr[p] = tmp;
}

Then just take the first items of the array, in order from 1 to the amount of results you want, because they are already shuffled randomly, and none repeats.

See example with results in jsFiddle

adapted response from https://stackoverflow.com/questions/10694668/javascript-to-generate-50-no-repeat-random-numbers


if you need few values:

This technique is efficient even with few values, in this case it is enough to shorten the loop to "shuffle" only the required amount of numbers:

for (p = quantidade; p;) {

In this way, only the first values, indicated by the variable quantidade, will be "shuffled".


about algorithm

This algorithm is the Fisher-Yates, as colleague @woliveirajr reinforced in the comments, and in another question, colleague @FabriDamazio found an interesting analysis comparing Fisher-Yates with brute-force shuffling.

Worth a read:

Analysis of a Brute-Force Shuffle

 20
Author: Bacco, 2017-05-23 12:37:35

I use this solution of mine for simplicity, since it uses the method sort () , native to the language:

var x = new Array(1000);
for(var i=1; i<1001; i++) {
    x[i] = i; 
}

x.sort(function(a,b){ return (Math.round(Math.random())-0.5); });

However, the method used by @ Bacco will always be faster, since it is not necessary to recreate the array.

 2
Author: , 2014-03-24 18:42:18

Or you can run this way:

function getRandom(maxNum, qtdMax) {
  let n = 1;
  const lista = [];
  const val = () => Math.floor(Math.random() * maxNum + 1);
  
  do {
    while (n <= qtdMax) {
      let numero = val();

      if (lista.indexOf(numero) === -1) {
        lista.push(numero)
      } else {n -= 1};
      n += 1
    };
  } while (lista.length < qtdMax);

  lista.sort((a, b) => a - b);
  console.log(lista);
  return lista;
}

getRandom(60, 6);

In the above example, I left to run a random combination of 6 digits (second parameter of the function) with value limit at 60 (First parameter of the function). So you can run the list only once for the amount of characters you want and the limit of the random number without doing so many iterations. Detail, I put a sort to arrange the list in an ascending way.

In a practical example, you can find the data by index in the For loop, or unstructuring:

const get = getRandom(60, 6);

for (const i in get) {
  const texto = `Index: ${i} = ${get[i]}`
  console.log(texto)
}

const [ num1 ] = get

console.log(num1)
 -1
Author: Rodrigo Brocchi, 2020-12-31 19:40:43