Genere números aleatorios únicos entre 1 y 100

99

¿Cómo puedo generar algunos números aleatorios únicos entre 1 y 100 usando JavaScript?

punteado
fuente
19
No es realmente un engaño, ya que se centra en javascript.
dotty
2
@dotty bueno, no hay una diferencia esencial entre hacer esto en Javascript y hacerlo en cualquier otro idioma, pero no votaré para cerrar.
Puntiagudo
1
Tampoco votaré para cerrar. Esto es suficientemente específico.
Josh Stodola
1
Hay otra forma más limpia de hacer esto stackoverflow.com/questions/51898200/…
Huangism

Respuestas:

174

Por ejemplo: para generar 8 números aleatorios únicos y almacenarlos en una matriz, simplemente puede hacer esto:

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
fuente
15
El código real es mucho mejor para tales preguntas que el pseudocódigo;) (eliminé mi respuesta que era pseudocódigo ...)
Roman Starkov
3
O puede ser elegido; use var randomnumber = Math.ceil (Math.random () * 100)
Alsciende
9
-1: este algoritmo es el enfoque ingenuo; es muy ineficiente.
Frerich Raabe
39
Guau. Ingenuo parece un poco fuerte. Puede que no sea la mejor solución, pero es simple, breve, fácil de ver lo que está sucediendo y se ejecuta dentro de parámetros operativos aceptables para lo que debe lograrse. Pasamos a la siguiente tarea. La perfección es genial, pero "hecho" es mejor que "perfecto".
adam0101
4
Existe la posibilidad de que la función devuelva un 0 en la matriz. Según este enlace: developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/… , Math.random () Returns a random number between 0 (inclusive) and 1 (exclusive). Si the Math.random()accidentalmente devuelve 0, Math.ceil(0)también es 0, aunque la probabilidad es baja.
Qian Chen
43
  1. Complete una matriz con los números del 1 al 100.
  2. Mezclarlo .
  3. Tome los primeros 8 elementos de la matriz resultante.
ЯegDwight
fuente
8
Seguramente es más eficiente modificar el código para hacer solo las primeras 8 repeticiones. (y luego tome los últimos 8 elementos de la matriz semi-aleatoria)
segundo
1
Así es como yo también lo hago siempre. Entonces, si quisiera diez líneas aleatorias de un archivo con un montón de líneas, lo hago randlines file | head -10.
tchrist
1
Creo que es la respuesta correcta, porque mantiene la distribución de probabilidad, que la respuesta aceptada no lo hace
roberto tomás
2
¿Y si N = 10 ^ 12? No muy eficiente.
Shinzou
2
@shinzou en el mundo real, no ordenarías 10 ^ 12 números usando JavaScript. Una pregunta tirival requiere una respuesta trivial. No estoy aquí para solucionar el hambre en el mundo. Estoy bien equipado para hacer eso, pero de eso no se trata la pregunta.
ЯegDwight
14

Genere la permutación de 100 números y luego elija en serie.

Utilice el algoritmo Knuth Shuffle (también conocido 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 DESDE LINK.

EDITAR :

Código mejorado:

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:

Supongamos que tenemos una matriz de 100 números {por ejemplo, [1,2,3 ... 100]} y dejamos de intercambiar después de 8 intercambios; entonces la mayoría de las veces la matriz se verá como {1,2,3,76,5,6,7,8, ... los números aquí se mezclarán ... 10}.

Porque todos los números se intercambiarán con una probabilidad de 1/100, así que prob. de intercambiar los primeros 8 números es 8/100 mientras que prob. de intercambiar otros 92 es 92/100.

Pero si ejecutamos el algoritmo para una matriz completa, entonces estamos seguros de que (casi) todas las entradas se intercambian.

De lo contrario nos enfrentamos a una pregunta: ¿qué 8 números elegir?

Pratik Deoghare
fuente
5
Este enfoque es correcto pero subóptimo: podría dejar de barajar después de ocho intercambios, ya que solo necesita ocho números aleatorios. El código anterior intercambia toda la matriz (en este escenario, 100 elementos).
Frerich Raabe
El código podría mejorarse seriamente. Los valores de retorno, los efectos secundarios y el uso de funciones son todos realmente borrosos en mi opinión. Quizás si escribe una función que responda exactamente al problema original, usando su función fisherYates, sería más claro.
Alsciende
1
Respuesta actualizada con código mejorado. Además, @Frerich Raabe: se menciona el problema de detenerse después de ocho intercambios.
Pratik Deoghare
Su algoritmo de Fisher-Yates es incorrecto. r debería depender de i. Ver mi respuesta: stackoverflow.com/questions/2380019/…
Alsciende
¡¡Uy, perdón por mi horrible error !! Tu implementación es genial. Le gustó. +1. Por favor, avíseme si algo más está mal. Gracias.
Pratik Deoghare
11

Solución JS moderna usando Set (y caso promedio O (n))

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

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

Alister
fuente
¿Por qué es O (n)? ¿No puede repetirse durante un período de tiempo arbitrario?
Anthony Wieser
@AnthonyWieser Tienes razón, en el peor de los casos. Estaba insinuando un caso promedio ya que Set.add es o (1)
Alister
Creo que esto podría devolver 0 como solía hacerlo mi respuesta antes de que se cambiara de usoMath.floor(Math.random()*100) + 1
adam0101
¡Es genial descubrirlo Seten JS! Sin embargo, ¿no causaría esta solución una generación innecesaria de números hasta que uno cumpla con el requisito de unicidad, especialmente en las últimas iteraciones, si 8 estuviera más cerca de 100? Por lo tanto, creo que prefiero la respuesta también elegante a sortcontinuación.
Gilad Barner
10

Las técnicas anteriores son buenas si desea evitar una biblioteca, pero dependiendo de si estaría bien con una biblioteca, le sugiero que consulte Chance para generar material aleatorio en JavaScript.

Específicamente para resolver su pregunta, usar Chance es tan fácil como:

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

Descargo de responsabilidad, como autor de Chance, soy un poco parcial;)

Víctor Quinn
fuente
Votar a favor porque nunca vi el fragmento de código de ejecución antes
surfmuggle
si quiero hacer un código (8 cadenas alfanuméricas aleatorias) para cupones, que tiene que ser único, ¿cómo puedo hacerlo con Chance.js? nota: los cupones se harán a pedido, por lo que la cantidad de códigos será indefinida
Oscar Yuandinata
@OscarYuandinata eso es fácil, solo hazlo var codes = chance.unique(chance.string, 8)Si necesitas los códigos extraídos de un grupo de caracteres en particular, puedes especificarlo de esta manera: chance.unique(chance.string, 8, {pool: "abcd1234"})donde abcd1234 puede ser cualquier carácter que quieras en el grupo. Ver chancejs.com/#string
Victor Quinn
@VictorQuinn, lo siento, no lo dije claramente. Quiero decir que el código del cupón será una cadena alfanumérica aleatoria de 8 caracteres, no una matriz de 8 cadenas alfanuméricas aleatorias. jajaja ..
Oscar Yuandinata
Oh @OscarYuandinata, eso es mucho más fácil, eh chance.string({ length: 8 })y si solo quieres que aparezcan ciertos caracteres en esa cadena, chance.string({ pool: 'abcd1234', length: 8 })que devolvería una cadena aleatoria de 8 caracteres de los caracteres abcd1234, por ejemplo, "2c2c44bc" o "331141cc"
Victor Quinn
8

Para evitar cambios largos y poco fiables, haría lo siguiente ...

  1. Genere una matriz que contenga el número entre 1 y 100, en orden.
  2. Genera un número aleatorio entre 1 y 100
  3. Busque el número en este índice en la matriz y guárdelo en sus resultados
  4. Quite el elemento de la matriz, haciéndolo uno más corto
  5. Repita desde el paso 2, pero use 99 como límite superior del número aleatorio
  6. Repita desde el paso 2, pero use 98 como límite superior del número aleatorio
  7. Repita desde el paso 2, pero use 97 como límite superior del número aleatorio
  8. Repita desde el paso 2, pero use 96 como límite superior del número aleatorio
  9. Repita desde el paso 2, pero use 95 como límite superior del número aleatorio
  10. Repita desde el paso 2, pero use 94 como límite superior del número aleatorio
  11. Repita desde el paso 2, pero use 93 como límite superior del número aleatorio

Voila, no hay números repetidos.

Puedo publicar algún código real más tarde, si alguien está interesado.

Editar: Probablemente sea la racha competitiva en mí, pero, habiendo visto la publicación de @Alsciende, no pude resistirme a publicar el código que prometí.

<!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
fuente
Pero entonces su octavo número es aleatorio del 1 al 92, no del 1 al 100. Si tuviera que elegir 90 números, su último número solo se elegiría del 1 al 10, ¿no es así?
adam0101
@ adam0101 No, porque elimina números a medida que los elige. Entonces, en el paso 5, solo hay 99 números en su matriz. @belugabob No eres más eficiente que Knuth Shuffle. De hecho, el empalme es probablemente más caro que el shuffle (que es perfectamente confiable)
Alsciende
@ adam0101: Está eliminando el elemento elegido de la matriz (consulte el paso 4 anterior), evitando así que cualquier elemento se elija dos veces. Luego usa un límite superior inferior para el siguiente número aleatorio, simplemente porque la matriz es más corta.
Frerich Raabe
@Alsciende, Sí. Pensó que habría una forma de hacer esto de manera más eficiente usando una reproducción aleatoria, pero no estaba completamente seguro. Para evitar eliminar el elemento de la matriz, simplemente copie la última entrada de la matriz (siempre que no sea la que eligió) en la posición que eligió.
belugabob
1
La razón para no disminuir values.length es que no hay garantía de que la disminución de la longitud de una matriz no se realice reasignando la memoria. Usar maxIndex tiene el mismo efecto, simplemente ignorando las últimas entradas en la matriz, ya que se vuelven irrelevantes.
belugabob
8

Otro enfoque es generar una matriz de 100 elementos con números ascendentes y ordenarlos al azar. En realidad, esto conduce a un fragmento muy corto y (en mi opinión) simple.

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

Felix Lemke
fuente
Esta es mi respuesta favorita de todas. No sé por qué obtuvo solo 6 votos. Elegante y con buena complejidad (siempre y cuando sortesté bien implementado, que estoy seguro).
Gilad Barner
3

Yo haría esto:

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;
Gumbo
fuente
3

Esta es una función muy genérica que he escrito para generar enteros aleatorios únicos / no únicos para una matriz. Suponga que el último parámetro es verdadero en este escenario para esta respuesta.

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

Aquí el 'tempObj' es un obj muy útil ya que cada número aleatorio generado verificará directamente en este tempObj si esa clave ya existe, si no, entonces reducimos la i en uno ya que necesitamos 1 ejecución adicional ya que el número aleatorio actual ya existe .

En su caso, ejecute lo siguiente

_arrayRandom(8, 1, 100, true);

Eso es todo.

kaizer1v
fuente
¿Qué pasará si quiero que se incluya 0? la línea min = (min) ? min : 1,siempre devolverá 1. (por lo que nunca se seleccionará 0)
TBE
Muy buen punto. :). Gracias, hice el cambio apropiado. Ahora regresará incluso si pasa un 0.
kaizer1v
2

Mezclar los números del 1 al 100 es la estrategia básica correcta, pero si solo necesita 8 números mezclados, no es necesario mezclar los 100 números.

No conozco muy bien Javascript, pero creo que es fácil crear una matriz de 100 nulos rápidamente. Luego, durante 8 rondas, intercambia el n-ésimo elemento de la matriz (n comenzando en 0) con un elemento seleccionado al azar de n + 1 a 99. Por supuesto, cualquier elemento que aún no se haya completado significa que el elemento realmente habría sido el índice original más 1, por lo que es trivial factorizar. Cuando haya terminado con las 8 rondas, los primeros 8 elementos de su matriz tendrán sus 8 números mezclados.

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

más corto que otras respuestas que he visto

FFF
fuente
1

El mismo algoritmo de permutación que The Machine Charmer, pero con una implementación prototipada. Se adapta mejor a una gran cantidad de picos. Utiliza la asignación de desestructuración js 1.7 si está disponible.

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

Editar: Otra propuesta, más adecuada para una pequeña cantidad de selecciones, basada en la respuesta de belugabob. Para garantizar la unicidad, eliminamos los números seleccionados de la 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
fuente
Buena implementación recursiva: publiqué una alternativa, en mi respuesta, que no usa empalme, ya que siento que este es un impacto de rendimiento evitable (no es que el OP tuviera problemas con el rendimiento)
belugabob
Su solución es inteligente, pero no la usaré en mi método Array # pick porque no quiero que esto tenga sus elementos mezclados cuando lo devuelva.
Alsciende
¿Qué matriz no desea que se mezcle, la matriz original 1-100 o los resultados? El primero no debería importar, ya que es una matriz de trabajo, y el segundo, por la naturaleza del código, saldrá en un orden aleatorio de todos modos. No estoy seguro de entender sus razones.
belugabob
El original. Implementé un método genérico Array # pick, que me parece útil. Esta función no sabe si esta es una matriz de trabajo o no. Para ser genérico, no altera esto más de lo necesario.
Alsciende
Pero todavía lo altera, aunque sea un poco, lo cual es inaccesible al usar esta técnica.
belugabob
1

para matrices con agujeros como este [,2,,4,,6,7,,] porque mi problema era llenar estos agujeros. Así que lo modifiqué según mi necesidad :)

la siguiente solución modificada funcionó para mí :)

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

La mejor respuesta anterior es la respuesta de sje397. Obtendrá los mejores números aleatorios que pueda obtener, lo más rápido posible.

Mi solución es muy similar a su solución. Sin embargo, a veces quieres los números aleatorios en orden aleatorio, y es por eso que decidí publicar una respuesta. Además, proporciono una función general.

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

Aquí está mi versión ES6 que improvisé. Seguro que se puede consolidar un poco más.

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

¿Qué tal usar las propiedades del objeto como una tabla hash ? De esta manera, su mejor escenario es aleatorizar solo 8 veces. Solo sería efectivo si desea una pequeña parte del rango de números. También requiere mucha menos memoria que Fisher-Yates porque no tiene que asignar espacio para una matriz.

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

Luego descubrí que Object.keys (obj) es una característica de ECMAScript 5, por lo que lo anterior es prácticamente inútil en Internet en este momento. No temas, porque lo hice compatible con ECMAScript 3 agregando una función 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
fuente
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
fuente
0

si necesita más exclusivo, debe generar una 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;
}

El código anterior es más 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
fuente
0

Añadiendo otra versión mejor del mismo código (respuesta aceptada) con la función indexOf de JavaScript 1.6. No es necesario recorrer toda la matriz cada vez que verifica el duplicado.

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

La versión anterior de Javascript aún puede usar la versión en la parte superior

PD: Intenté sugerir una actualización de la wiki pero fue rechazada. Sigo pensando que puede ser útil para otros.

software.wikipedia
fuente
0

Esta es mi solución personal:

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

Genera aleatoriamente 8 valores de matriz únicos (entre 0 y 7), luego los muestra usando un cuadro de alerta.

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

Creo que este método es diferente de los métodos dados en la mayoría de las respuestas, así que pensé que podría agregar una respuesta aquí (aunque la pregunta se hizo hace 4 años).

Generamos 100 números aleatorios y etiquetamos cada uno de ellos con números del 1 al 100. Luego clasificamos estos números aleatorios etiquetados y las etiquetas se mezclan aleatoriamente. Alternativamente, según sea necesario en esta pregunta, se podría eliminar simplemente encontrar los 8 primeros números aleatorios etiquetados. Encontrar los 8 elementos principales es más barato que ordenar toda la matriz.

Hay que señalar aquí que el algoritmo de clasificación influye en este algoritmo. Si el algoritmo de clasificación utilizado es estable, existe un ligero sesgo a favor de números más pequeños. Idealmente, querríamos que el algoritmo de clasificación fuera inestable y ni siquiera sesgado hacia la estabilidad (o inestabilidad) para producir una respuesta con una distribución de probabilidad perfectamente uniforme.

Kartik Kale
fuente
0

Esto puede manejar la generación de un número aleatorio ÚNICO de hasta 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);

ingrese la descripción de la imagen aquí

jsFiddle

Nofi
fuente
0

Esta solución utiliza el hash, que es mucho más eficaz O (1) que comprobar si reside en la matriz. También tiene controles de seguridad adicionales. Espero eso ayude.

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

Implementar esto como un generador hace que sea bastante agradable trabajar con él. Tenga en cuenta que esta implementación difiere de las que requieren que la matriz de entrada completa se mezcle primero.

Esta samplefunción funciona de manera perezosa, lo que le brinda 1 elemento aleatorio por iteración hasta los Nelementos que solicita. Esto es bueno porque si solo desea 3 elementos de una lista de 1000 , no tiene que tocar los 1000 elementos primero.

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

Elegí implementar samplede una manera que no mute la matriz de entrada, pero se podría argumentar fácilmente que una implementación mutante es favorable.

Por ejemplo, es posible que la shufflefunción desee mutar la matriz de entrada original. O tal vez desee tomar muestras de la misma entrada en varios momentos, actualizando la entrada 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]

sampleya no es una función pura debido a la mutación de entrada de la matriz, pero en ciertas circunstancias (como se demostró anteriormente) podría tener más sentido.


Otra razón por la que elegí un generador en lugar de una función que solo devuelve una matriz es porque es posible que desee continuar muestreando hasta alguna condición específica.

Quizás quiero el primer número primo de una lista de 1.000.000 de números aleatorios.

  • "¿Cuántos debo probar?" - no tienes que especificar
  • "¿Tengo que encontrar primero todos los números primos y luego seleccionar un primo aleatorio?" - No.

Como estamos trabajando con un generador, esta tarea es trivial.

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

Esto muestreará continuamente 1 número aleatorio a la vez x, verificará si es primo y luego devolverá xsi lo es. Si la lista de números se agota antes de encontrar un primo, NaNse devuelve.


Nota:

Esta respuesta se compartió originalmente en otra pregunta que se cerró como un duplicado de esta. Debido a que es muy diferente de las otras soluciones proporcionadas aquí, he decidido compartirlo aquí también.

Gracias
fuente
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
fuente
0

Usar a Setes la opción más rápida. Aquí hay una función genérica para obtener un aleatorio único que usa un generador de devolución de llamada. Ahora es rápido y reutilizable .

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

Esta es una implementación de Fisher Yates / Durstenfeld Shuffle , pero sin la creación real de una matriz, lo que reduce la complejidad del espacio o la memoria necesaria, cuando el tamaño de selección es pequeño en comparación con la cantidad de elementos disponibles.

Para elegir 8 números de 100, no es necesario crear una matriz de 100 elementos.

Suponiendo que se crea una matriz,

  • Desde el final de la matriz (100), obtenga un número aleatorio ( rnd) de 1 a 100
  • Intercambia 100 y el número aleatorio rnd
  • Repita el paso 1 con la matriz (99)

Si no se crea una matriz, se puede usar un hashMap para recordar las posiciones intercambiadas reales. Cuando el segundo número aleatorio generado es igual al de los números generados anteriormente, el mapa proporciona el valor actual en esa posición en lugar del 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)));

El maestro
fuente
0

Aquí hay un ejemplo de 5 números aleatorios tomados de un rango de 0 a 100 (tanto 0 como 100 incluidos) sin duplicación.

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

También puedes hacerlo con un trazador de líneas 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
fuente
Por la pureza de no ceder nada.
Marcin Król