Comment choisir un ensemble de nombres aléatoires uniques (pas de doublons) à l'aide de la méthode jQuery.inArray?

Il s'agit d'une question Javascript / jQuery:

J'essaie de générer six nombres aléatoires uniques entre 1 et 21 (pas de doublons), en utilisant la méthode jQuery.inArray . Ces six nombres seront ensuite utilisés pour sélectionner six fichiers .jpg à partir d'un groupe nommé logo1.jpg via logo21.jpg.

Quelqu'un peut-il me dire ce que je fais mal ici?

<div id="client-logos"></div> <script src="http://code.jquery.com/jquery-1.5.js"></script> <script type="text/javascript"> Show = 6; // Number of logos to show TotalLogos = 21; // Total number of logos to choose from FirstPart = '<img src="/wp-content/client-logos/logo'; LastPart = '.jpg" height="60" width="120" />'; r = new Array(Show); // Random number array var t=0; for (t=0;t<Show;t++) { while ( jQuery.inArray(x,r) { var x = Math.ceil(Math.random() * TotalLogos); }); r[t] = x; var content = document.getElementById('client-logos').innerHTML; document.getElementById('client-logos').innerHTML = content + FirstPart + r[t] + LastPart; } </script> 

Merci d'avance…

Vous avez quelques problèmes là-bas:

  • Variables dans la portée de la fenêtre globale

  • Un tableau déclaré avec le new mot-clé au lieu d'un littéral

  • Essayer d'utiliser les variables avant de les déclarer

  • JQuery.inArray est mal utilisé ( inArray renvoie un nombre , pas true ou false )

  • Code inefficace avec une boucle while qui théoriquement pourrait conduire à une boucle infinie

Maintenant, le second combiné avec le troisième est le problème principal ici, comme la première fois que vous testez x dans le tableau, il est undefined (vous ne le définissez que dans l'instruction if avec var , donc le x est au premier indéfini) Et donc il correspond au premier élément du tableau (qui est undefined comme vous l'avez déclaré avec une new Array(6) ) et la fonction inArray renvoie 1, ce qui conduit à une boucle infinie.

Il existe plusieurs choses que vous pourriez faire pour corriger ce code, mais je pense qu'une réécriture complète avec une approche différente pourrait être meilleure et ne nécessite aucun jQuery.

Cette version modifiée de votre code devrait fonctionner correctement:

 var Show = 6, // Number of logos to show TotalLogos = 21, // Total number of logos to choose from FirstPart = '<img src="/wp-content/client-logos/logo', LastPart = '.jpg" height="60" width="120" />', array = [], // array with all avaiilable numbers rnd, value, i, logosElement = document.getElementById('client-logos'); for (i = 0; i < TotalLogos; i++) { // arrays are zero based, for 21 elements you want to go from index 0 to 20. array[i] = i + 1; } for (i = 0; i < Show; i++) { // pick numbers rnd = Math.floor(Math.random() * array.length); value = array.splice(rnd,1)[0]; // remove the selected number from the array and get it in another variable logosElement.innerHTML += (FirstPart + value + LastPart); } 

Pour expliquer un peu ce que j'ai fait ici:

  • Initialiser un tableau avec toutes les valeurs possibles que vous avez (numéros 1 à 21)

  • Exécutez une boucle autant de fois que les nombres que vous souhaitez choisir.

  • Génère un nombre aléatoire de 0 à l'index maximum disponible dans votre tableau de nombres

  • Supprimez le nombre à cet index du tableau à l'aide de l'épissage, puis utilisez-le pour créer la chaîne pour l'appel innerHTML (l' épissure renvoie les éléments supprimés du tableau en tant que nouvel ensemble ).

  • En outre, la variable logosElement est mise en cache au début, de sorte que vous ne faites qu'une seule recherche de DOM pour l'élément.

Il y a plus de façons dont le code peut être réécrit et même nettoyé, mais j'ai pensé que ce serait le moyen le plus propre de vous aider à résoudre votre problème (et il est sécurisé pour tous les navigateurs sans avoir à ajouter jQuery, sauf si vous en avez besoin pour une autre fonctionnalité)

La raison immédiatement évidente pour laquelle il ne fonctionne pas, autrement que la parenthèse de fermeture supplémentaire après votre boucle de temps, est un léger malentendu sur la façon $.inArray méthode $.inArray fonctionne. $.inArray renvoie le premier index d'une valeur correspondante dans le tableau, ou -1 s'il n'est pas trouvé. -1 est une valeur "vérité", ce qui signifie while votre boucle while continuera l'exécution si le nombre aléatoire n'est pas dans le tableau . En fait, il continuera l'exécution jusqu'à ce qu'il trouve le numéro au 0ème emplacement du tableau.

Pour résoudre ce problème particulier, vous devez vérifier qu'il est supérieur à -1, ainsi que définir le var x à un nombre aléatoire avant la boucle:

 var x = Math.ceil(Math.random() * TotalLogos); while ($.inArray(x, r) > -1) { x = Math.ceil(Math.random() * TotalLogos); } r[t] = x; 

Dans les réponses aux commentaires de votre question, Pointy mentionne également le Fisher-Yates Shuffle. Cette méthode de brassage peut vous offrir une meilleure distribution que l'approche que vous utilisez.

 // Initial number var x = Math.ceil(Math.random() * TotalLogos); // Keep searching until a unique number is found while ($.inArray(x, r) > -1) { x = Math.ceil(Math.random() * TotalLogos); } // If it's unique, set it r[t] = x;