Как выбрать набор уникальных случайных чисел (без дубликатов), используя метод jQuery.inArray? - PullRequest
4 голосов
/ 28 февраля 2011

Это вопрос Javascript / jQuery:

Я пытаюсь сгенерировать шесть уникальных случайных чисел от 1 до 21 (без дубликатов), используя метод jQuery.inArray .Затем эти шесть чисел будут использованы для выбора шести файлов .jpg из группы с именами от logo1.jpg до logo21.jpg.

Кто-нибудь может сказать мне, что я здесь не так делаю?

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

Заранее спасибо ...

Ответы [ 3 ]

4 голосов
/ 28 февраля 2011

у вас есть несколько проблем:

  • переменные в области глобального окна

  • массив, объявленный с ключевым словом newлитерала

  • , пытающегося использовать переменные перед объявлением их

  • jQuery.inArray, который используется неправильно ( inArray возвращает число , а не true или false)

  • неэффективный код с циклом while, который теоретически может привести к бесконечному циклу

теперь, второе в сочетании с третьим является главной проблемой здесь, так как при первом тестировании x в массиве это undefined (вы определяете его только внутри if с помощью оператора varтаким образом, x сначала не определен) и, таким образом, он соответствует первому элементу в массиве (который равен undefined, как вы объявили r с new Array(6)), и функция inArray возвращает 1, что приводит к бесконечному циклу.

Есть несколько вещей, которые вы можете сделать, чтобы исправить этот код, но я думаю,полное переписывание с другим подходом может быть лучше и вообще не требует jQuery.

Эта модифицированная версия вашего кода должна работать нормально:

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


Чтобы объяснить немного, что я сделал здесь:

  • инициализируйте массив всеми возможными значениями (числа от 1 до 21)

  • запустите цикл только столько раз, сколько вы хотите выбрать.

  • сгенерируйте случайное число от 0 до максимального индекса, доступного в вашем массиве чисел

  • удаляет число по этому индексу из массива с помощью splice, а затем использует его для создания строки для вызова innerHTML ( splice возвращает элементы, удаленные из массива, как еще один новый массив ).

  • Кроме того, переменная logosElement кэшируется в начале, поэтому вы выполняете только один DOM-поиск для элемента.

Есть и другие способыэтот код может быть переписан и даже очищен, но я решилэто был бы самый чистый способ помочь вам с вашей проблемой (и это кросс-браузер безопасно!нет необходимости добавлять jQuery, если вам не нужен другой функционал)

0 голосов
/ 28 февраля 2011

Непосредственной причиной того, что он не работает, кроме дополнительной закрывающей скобки после цикла while, является небольшое недопонимание того, как работает метод $.inArray.$.inArray возвращает первый индекс соответствующего значения в массиве или -1, если он не найден.-1 - это «истинное» значение, означающее, что ваш цикл while продолжит выполнение, если случайное число отсутствует в массиве .Фактически, он продолжит выполнение, пока не найдет число в 0-м месте массива.

Чтобы решить эту конкретную проблему, вам нужно проверить, что она больше -1, а также установить переменную x в случайное число перед циклом:

var x = Math.ceil(Math.random() * TotalLogos);

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

В комментарии, отвечающем на ваш вопрос, Пойнти также упоминает случайную игру Фишера-Йейтса.Этот метод перетасовки может дать вам лучшее распределение, чем тот, который вы используете.

0 голосов
/ 28 февраля 2011
// 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;
...