Générez des nombres aléatoires uniques entre 1 et 100


99

Comment générer des nombres aléatoires uniques entre 1 et 100 en utilisant JavaScript?


19
Pas vraiment dupe car il se concentre sur javascript.
dotty

2
@dotty eh bien, il n'y a pas de différence essentielle entre faire cela en Javascript et le faire dans une autre langue, mais je ne voterai pas pour fermer.
Pointy

1
Je ne voterai pas non plus pour fermer. C'est assez précis.
Josh Stodola


1
Il existe une autre façon plus propre de faire ce stackoverflow.com/questions/51898200/…
Huangism

Réponses:


174

Par exemple: pour générer 8 nombres aléatoires uniques et les stocker dans un tableau, vous pouvez simplement faire ceci:

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


15
Le code réel est tellement meilleur pour de telles questions que le pseudocode;) (supprimé ma réponse qui était le pseudocode ...)
Roman Starkov

3
O peut être choisi; utilisez var randomnumber = Math.ceil (Math.random () * 100)
Alsciende

9
-1: cet algorithme est l'approche naïve; c'est très inefficace.
Frerich Raabe

39
Sensationnel. Naïf semble un peu fort. Ce n'est peut-être pas la meilleure solution, mais elle est simple, courte, facile à voir ce qui se passe et fonctionne avec des paramètres de fonctionnement acceptables pour ce qui doit être accompli. Passons à la tâche suivante. La perfection est grande, mais «fait» est mieux que «parfait».
adam0101

4
Il y a une chance que la fonction renvoie un 0 dans le tableau. Selon ce lien: 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()accidentellement renvoie 0, le Math.ceil(0)vaut également 0, bien que la chance soit faible.
Qian Chen

43
  1. Remplissez un tableau avec les nombres 1 à 100.
  2. Mélangez-le .
  3. Prenez les 8 premiers éléments du tableau résultant.

8
il est sûrement plus efficace de modifier le code pour ne faire que les 8 premiers shuffles? (puis prenez les 8 derniers éléments du tableau semi-mélangé)
deuxième

1
C'est ainsi que je le fais toujours aussi. Donc si je voulais dix lignes aléatoires à partir d'un fichier contenant un tas de lignes, je le fais randlines file | head -10.
tchrist

1
Je pense que c'est la bonne réponse, car elle maintient la distribution de probabilité, ce que la réponse acceptée ne fait pas
roberto tomás

2
Et si N = 10 ^ 12? Pas très efficace.
shinzou

2
@shinzou dans le monde réel, vous ne trieriez pas 10 ^ 12 nombres en utilisant JavaScript. Une question tirival appelle une réponse triviale. Je ne suis pas ici pour résoudre la faim dans le monde. Je suis bien équipé pour le faire, mais ce n’est pas là la question.
ЯegDwight

14

Générez une permutation de 100 nombres, puis choisissez en série.

Utilisez l' algorithme Knuth Shuffle (alias le mélange Fisher-Yates) .

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;

   }
}

CODE COPIÉ À PARTIR DU LIEN.

MODIFIER :

Code amélioré:

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

Problème potentiel:

Supposons que nous ayons un tableau de 100 nombres {par exemple [1,2,3 ... 100]} et que nous arrêtions d'échanger après 8 swaps; alors la plupart du temps, le tableau ressemblera à {1,2,3,76,5,6,7,8, ... les nombres ici seront mélangés ... 10}.

Parce que chaque nombre sera échangé avec une probabilité de 1/100 donc prob. d'échanger les 8 premiers nombres est 8/100 alors que prob. de l'échange des 92 autres est de 92/100.

Mais si nous exécutons un algorithme pour un tableau complet, nous sommes sûrs (presque) que chaque entrée est permutée.

Sinon, nous sommes confrontés à une question: quels 8 numéros choisir?


5
Cette approche est correcte mais sous-optimale: vous pouvez arrêter la lecture aléatoire après huit échanges, car vous n'avez besoin que de huit nombres aléatoires. Le code ci-dessus permute le tableau entier (dans ce scénario, 100 éléments).
Frerich Raabe

Le code pourrait être sérieusement amélioré. Les valeurs de retour, les effets secondaires et l'utilisation des fonctions sont tous vraiment flous IMO. Peut-être que si vous écrivez une fonction qui répond exactement au problème d'origine, en utilisant votre fonction fisherYates, ce serait plus clair.
Alsciende

1
Réponse mise à jour avec un code amélioré. Aussi, @Frerich Raabe: un problème d'arrêt après huit échanges est mentionné.
Pratik Deoghare

Votre algorithme Fisher-Yates est erroné. r devrait dépendre de i. Voir ma réponse: stackoverflow.com/questions/2380019/…
Alsciende

Oups désolé mon horrible erreur !! Votre mise en œuvre est cool. Aimé. +1. S'il vous plaît laissez-moi savoir si quelque chose ne va pas avec cela.Merci.
Pratik Deoghare

11

Solution JS moderne utilisant Set (et cas moyen O (n))

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

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


Pourquoi est-ce O (n)? Ne peut-il pas faire une boucle pendant une durée arbitraire?
Anthony Wieser

@AnthonyWieser Vous avez raison, le pire des cas. J'impliquais un cas moyen puisque Set.add est o (1)
Alister

Je pense que cela pourrait renvoyer 0 comme ma réponse avant qu'elle ne soit modifiéeMath.floor(Math.random()*100) + 1
adam0101

Très cool à découvrir Setdans JS! Cependant, cette solution ne provoquerait-elle pas une génération inutile de nombres jusqu'à ce que l'on réponde à l'exigence d'unicité, en particulier dans les dernières itérations, si 8 était plus proche de 100? Je pense donc que je préfère la réponse également élégante sortci-dessous.
Gilad Barner

10

Les techniques ci-dessus sont bonnes si vous voulez éviter une bibliothèque, mais selon si vous êtes d'accord avec une bibliothèque, je suggérerais de vérifier Chance pour générer des éléments aléatoires en JavaScript.

Plus précisément, pour résoudre votre question, utiliser Chance est aussi simple que:

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

Clause de non-responsabilité, en tant qu'auteur de Chance, je suis un peu partial;)


Vote positif parce que je n'ai jamais vu l'extrait de code d'exécution auparavant
surfmuggle

si je veux créer un code (8 chaînes alphanumériques aléatoires) pour les coupons, qui doit être unique, comment puis-je le faire avec Chance.js? note: les coupons seront effectués sur demande, donc le nombre de codes sera indéfini
Oscar Yuandinata

@OscarYuandinata c'est facile, faites simplement. var codes = chance.unique(chance.string, 8)Si vous avez besoin des codes extraits d'un pool de caractères particulier, vous pouvez le spécifier comme ceci: chance.unique(chance.string, 8, {pool: "abcd1234"})où abcd1234 peut être n'importe quel caractère du pool. Voir chancejs.com/#string
Victor Quinn

@VictorQuinn, désolé je n'ai pas été clair. Je veux dire que le code de coupon sera une chaîne alphanumérique aléatoire de 8 caractères, pas un tableau de 8 chaînes alphanumériques aléatoires. hahaha ..
Oscar Yuandinata

Oh @OscarYuandinata c'est beaucoup plus facile heh chance.string({ length: 8 })et si vous voulez seulement que certains caractères apparaissent dans cette chaîne, chance.string({ pool: 'abcd1234', length: 8 })ce qui renverrait une chaîne aléatoire de 8 caractères à partir des caractères abcd1234, donc par exemple "2c2c44bc" ou "331141cc"
Victor Quinn

8

Pour éviter tout mélange long et peu fiable, je ferais ce qui suit ...

  1. Générez un tableau contenant le nombre entre 1 et 100, dans l'ordre.
  2. Générer un nombre aléatoire entre 1 et 100
  3. Recherchez le numéro à cet index dans le tableau et enregistrez-le dans vos résultats
  4. Retirez l'élément du tableau, ce qui le raccourcit
  5. Répétez à partir de l'étape 2, mais utilisez 99 comme limite supérieure du nombre aléatoire
  6. Répétez à partir de l'étape 2, mais utilisez 98 comme limite supérieure du nombre aléatoire
  7. Répétez à partir de l'étape 2, mais utilisez 97 comme limite supérieure du nombre aléatoire
  8. Répétez à partir de l'étape 2, mais utilisez 96 comme limite supérieure du nombre aléatoire
  9. Répétez à partir de l'étape 2, mais utilisez 95 comme limite supérieure du nombre aléatoire
  10. Répétez à partir de l'étape 2, mais utilisez 94 comme limite supérieure du nombre aléatoire
  11. Répétez à partir de l'étape 2, mais utilisez 93 comme limite supérieure du nombre aléatoire

Voila - pas de nombres répétés.

Je pourrais publier du code plus tard, si quelqu'un est intéressé.

Edit: C'est probablement la séquence de compétition en moi mais, après avoir vu le message de @Alsciende, je n'ai pas pu résister à la publication du code que j'avais promis.

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


Mais alors votre huitième nombre est aléatoire de 1 à 92, pas de 1 à 100. Si vous deviez choisir 90 nombres, votre dernier nombre ne serait choisi que de 1 à 10, n'est-ce pas?
adam0101

@ adam0101 Non, car il supprime les nombres au fur et à mesure qu'il les choisit. Donc à l'étape 5, il n'y a que 99 nombres dans son tableau. @belugabob Vous n'êtes pas plus efficace que Knuth Shuffle. En fait, l'épissure est probablement plus chère que le shuffle (qui est parfaitement fiable)
Alsciende

@ adam0101: Il supprime l'élément choisi du tableau (voir l'étape 4 ci-dessus), évitant ainsi que des éléments soient choisis deux fois. Il utilise ensuite une borne supérieure inférieure pour le prochain nombre aléatoire, simplement parce que le tableau est plus court.
Frerich Raabe

@Alsciende, Oui - pensait qu'il y aurait un moyen de le faire plus efficacement en utilisant un mélange, mais n'était pas complètement sûr. Pour éviter de supprimer l'élément du tableau, copiez simplement la dernière entrée du tableau (à condition que ce ne soit pas celui que vous avez choisi) dans la position que vous avez choisie.
belugabob

1
La raison pour laquelle on ne décrémente pas values.length est qu'il n'y a aucune garantie que la diminution de la longueur d'un tableau ne se fasse pas en réallouant de la mémoire. L'utilisation de maxIndex a le même effet, en ignorant simplement les dernières entrées du tableau, car elles ne sont plus pertinentes.
belugabob

8

Une autre approche consiste à générer un tableau de 100 éléments avec des nombres croissants et à le trier au hasard. Cela conduit en fait à un extrait de code très court et (à mon avis) simple.

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


C'est ma réponse préférée de toutes. Je ne sais pas pourquoi il n'a obtenu que 6 votes. Élégant et avec une bonne complexité (à condition qu'il sortsoit bien implémenté, ce que je suis sûr que c'est).
Gilad Barner

3

Je ferais ceci:

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;

3

C'est une fonction très générique que j'ai écrite pour générer des entiers aléatoires uniques / non uniques pour un tableau. Supposons que le dernier paramètre soit vrai dans ce scénario pour cette réponse.

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

Ici, le 'tempObj' est un obj très utile car chaque nombre aléatoire généré vérifiera directement dans ce tempObj si cette clé existe déjà, sinon, nous réduisons le i de un car nous avons besoin d'une exécution supplémentaire puisque le nombre aléatoire actuel existe déjà .

Dans votre cas, exécutez ce qui suit

_arrayRandom(8, 1, 100, true);

C'est tout.


que se passera-t-il si je veux que 0 soit inclus? la ligne min = (min) ? min : 1,renvoie toujours 1. (donc 0 ne sera jamais sélectionné)
TBE

Un très bon point. :). Merci, j'ai fait le changement approprié. Il reviendra maintenant même si vous passez dans un 0.
kaizer1v

2

Mélanger les nombres de 1 à 100 est la bonne stratégie de base, mais si vous n'avez besoin que de 8 nombres mélangés, il n'est pas nécessaire de mélanger les 100 nombres.

Je ne connais pas très bien Javascript, mais je pense qu'il est facile de créer rapidement un tableau de 100 null. Ensuite, pendant 8 tours, vous permutez le nième élément du tableau (n commençant à 0) avec un élément sélectionné aléatoirement de n + 1 à 99. Bien sûr, tout élément non encore rempli signifie que l'élément aurait vraiment été l'index d'origine plus 1, donc c'est facile à prendre en compte. Lorsque vous avez terminé avec les 8 tours, les 8 premiers éléments de votre tableau auront vos 8 nombres mélangés.


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

plus court que les autres réponses que j'ai vues


1

Même algorithme de permutation que The Machine Charmer, mais avec une implémentation prototypée. Mieux adapté à un grand nombre de pics. Utilise l' affectation de déstructuration js 1.7 si 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);

Edit: Une autre proposition, mieux adaptée à un petit nombre de choix, basée sur la réponse de belugabob. Pour garantir l'unicité, nous supprimons les nombres sélectionnés du tableau.

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

Belle implémentation récursive - j'ai publié une alternative, dans ma réponse, qui n'utilise pas d'épissure, car je pense que c'est un coup de performance évitable (pas que l'OP ait eu des problèmes de performances)
belugabob

Votre solution est intelligent, mais je ne vais pas l' utiliser dans mon tableau # choisir la méthode parce que je ne veux pas cela pour avoir ses éléments bousculés quand je le retourne.
Alsciende

Quel tableau ne voulez-vous pas mélanger, le tableau 1-100 d'origine ou les résultats? Le premier ne devrait pas avoir d'importance, car il s'agit d'un tableau fonctionnel, et le second, par la nature du code, sortira de toute façon dans un ordre aléatoire. Je ne suis pas sûr de comprendre vos raisons.
belugabob

L'original. J'ai implémenté une méthode générique de sélection Array #, que je trouve utile. Cette fonction ne sait pas si c'est un tableau de travail ou non. Pour être générique, il ne modifie pas ce plus que nécessaire.
Alsciende

Mais cela le modifie encore, même si ce n'est que peu, ce qui est inévitable lors de l'utilisation de cette technique.
belugabob

1

pour les tableaux avec des trous comme celui-ci [,2,,4,,6,7,,] car mon problème était de combler ces trous. Alors je l'ai modifié selon mes besoins :)

la solution modifiée suivante a fonctionné pour moi :)

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

1

La meilleure réponse antérieure est la réponse par sje397. Vous obtiendrez des nombres aléatoires aussi bons que possible, aussi vite que possible.

Ma solution est très similaire à sa solution. Cependant, parfois, vous voulez les nombres aléatoires dans un ordre aléatoire, et c'est pourquoi j'ai décidé de publier une réponse. De plus, j'assure une fonction générale.

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

1

Voici ma version ES6 que j'ai bricolée. Je suis sûr que cela peut être un peu plus consolidé.

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


0

Que diriez-vous d'utiliser les propriétés d'objet comme table de hachage ? De cette façon, votre meilleur scénario est de ne randomiser que 8 fois. Ce ne serait efficace que si vous voulez une petite partie de la plage de nombres. Il est également beaucoup moins gourmand en mémoire que Fisher-Yates car vous n'avez pas à allouer d'espace pour un tableau.

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

J'ai alors découvert que Object.keys (obj) est une fonctionnalité ECMAScript 5, donc ce qui précède est pratiquement inutile sur les internets pour le moment. N'ayez crainte, car je l'ai rendu compatible ECMAScript 3 en ajoutant une fonction de touches comme celle-ci.

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

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

0

si vous avez besoin de plus d'unique, vous devez générer un tableau (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;
}

le code ci-dessus est plus rapide:
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]


0

Ajout d'une autre version améliorée du même code (réponse acceptée) avec la fonction JavaScript 1.6 indexOf. Vous n'avez pas besoin de parcourir tout le tableau à chaque fois que vous vérifiez le doublon.

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 version plus ancienne de Javascript peut toujours utiliser la version en haut

PS: J'ai essayé de suggérer une mise à jour du wiki mais cela a été rejeté. Je pense toujours que cela peut être utile pour les autres.


0

Voici ma solution personnelle:

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

Il génère au hasard 8 valeurs de tableau uniques (entre 0 et 7), puis les affiche à l'aide d'une boîte d'alerte.


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

Je pense que cette méthode est différente des méthodes données dans la plupart des réponses, alors j'ai pensé que je pourrais ajouter une réponse ici (bien que la question ait été posée il y a 4 ans).

Nous générons 100 nombres aléatoires et étiquetons chacun d'eux avec des nombres de 1 à 100. Ensuite, nous trions ces nombres aléatoires étiquetés, et les étiquettes sont mélangées au hasard. Alternativement, au besoin dans cette question, on pourrait se passer de trouver simplement les 8 premiers des nombres aléatoires marqués. Trouver les 8 meilleurs articles coûte moins cher que de trier l'ensemble de la gamme.

Il faut noter ici que l'algorithme de tri influence cet algorithme. Si l'algorithme de tri utilisé est stable, il y a un léger biais en faveur de nombres plus petits. Idéalement, nous voudrions que l'algorithme de tri soit instable et même pas biaisé vers la stabilité (ou l'instabilité) pour produire une réponse avec une distribution de probabilité parfaitement uniforme.


0

Cela peut gérer la génération d'un nombre aléatoire UNIQUE jusqu'à 20 chiffres

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

entrez la description de l'image ici

jsFiddle


0

Cette solution utilise le hachage qui est beaucoup plus performant O (1) que de vérifier si le réside dans le tableau. Il a également des contrôles plus sûrs. J'espère que ça aide.

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

0

L'implémenter en tant que générateur le rend assez agréable à utiliser. Notez que cette implémentation diffère de celles qui nécessitent que le tableau d'entrée entier soit d'abord mélangé.

Cette samplefonction fonctionne paresseusement, vous donnant 1 élément aléatoire par itération jusqu'aux Néléments que vous demandez. C'est bien car si vous ne voulez que 3 éléments sur une liste de 1000 , vous n'avez pas à toucher les 1000 éléments en premier.

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

J'ai choisi d'implémenter sampled'une manière qui ne mute pas le tableau d'entrée, mais vous pourriez facilement affirmer qu'une implémentation en mutation est favorable.

Par exemple, la shufflefonction peut souhaiter muter le tableau d'entrée d'origine. Ou vous souhaiterez peut-être échantillonner à partir de la même entrée à différents moments, en mettant à jour l'entrée à chaque fois.

// 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'est plus une fonction pure à cause de la mutation d'entrée du tableau, mais dans certaines circonstances (démontrées ci-dessus), cela pourrait avoir plus de sens.


Une autre raison pour laquelle j'ai choisi un générateur au lieu d'une fonction qui renvoie simplement un tableau est que vous souhaiterez peut-être continuer à échantillonner jusqu'à une condition spécifique.

Peut-être que je veux le premier nombre premier d'une liste de 1 000 000 de nombres aléatoires.

  • "Combien dois-je en échantillonner?" - vous n'avez pas à spécifier
  • "Dois-je d'abord trouver tous les nombres premiers, puis sélectionner un nombre premier aléatoire?" - Nan.

Parce que nous travaillons avec un générateur, cette tâche est triviale

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

Cela va échantillonner en continu 1 nombre aléatoire à la fois, xvérifier s'il est premier, puis revenir xs'il l'est. Si la liste de nombres est épuisée avant qu'un premier ne soit trouvé, NaNest retourné.


Remarque:

Cette réponse a été partagée à l'origine sur une autre question qui a été fermée comme un double de celle-ci. Parce que c'est très différent des autres solutions proposées ici, j'ai décidé de le partager ici aussi


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
}

0

L'utilisation de a Setest votre option la plus rapide. Voici une fonction générique pour obtenir un aléatoire unique qui utilise un générateur de rappel. Maintenant, c'est rapide et réutilisable .

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


0

Il s'agit d'une implémentation de Fisher Yates / Durstenfeld Shuffle , mais sans création réelle d'un tableau, réduisant ainsi la complexité de l'espace ou la mémoire nécessaire, lorsque la taille de sélection est petite par rapport au nombre d'éléments disponibles.

Pour choisir 8 nombres parmi 100, il n'est pas nécessaire de créer un tableau de 100 éléments.

En supposant qu'un tableau est créé,

  • À partir de la fin du tableau (100), obtenez un nombre aléatoire ( rnd) de 1 à 100
  • Swap 100 et le nombre aléatoire rnd
  • Répétez l'étape 1 avec le tableau (99)

Si un tableau n'est pas créé, un hashMap peut être utilisé pour se souvenir des positions échangées réelles. Lorsque le deuxième nombre aléatoire généré est égal à l'un des nombres précédemment générés, la carte fournit la valeur actuelle à cette position plutôt que la valeur réelle.

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


0

Voici un exemple de 5 nombres aléatoires pris dans une plage de 0 à 100 (0 et 100 inclus) sans duplication.

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)

-1

Vous pouvez également le faire avec une seule doublure comme celle-ci:

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


Pour la pureté de ne rien assigner.
Marcin Król
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.